2

Goal: Develop a WebSocket + AngularJS client

My goal is to create a WebSocket client using AngularJS, the program is expected to send a message to the java server which replies with the same message and the date.

  • The server side works fine (it is shown below, (implemented using java)
  • I have tested it with a regular javascript web socket program)

My issue:

The client-side with AngularJS doesn't work.

  • Maybe I used the wrong library for this project.

Here is the WebSocket library I use for AngularJS :

https://github.com/AngularClass/angular-websocket

Client side - this doesn't work - what am I doing wrong?

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src="lib/angular.min.js"></script>
<script type="text/javascript" src="lib/angular-websocket.js"></script>
<script type="text/javascript">
var app = angular.module('websocket',[]);
app.service('WebSocketWrapper', ['$log', '$websocket', '$rootScope', function($log, $websocket, $rootScope){
this.ws = null; // Attach ws to service object
this.state = 'initializing';
this.message = 'websocket initializing';
var self = this;
this.init = function(){
    if(!this.ws){
        this.ws = $websocket('ws://127.0.0.1:8080/WebSocketHome/echo', null, {reconnectIfNorNormalClose: true});

        this.ws.onClose(function(){
            console.info('close');
            $rootScope.$apply(function(){
                self.state = 'disconnected';
                self.message = 'Websocket disconnected';
            });
        });

        this.ws.onOpen(function(){
            console.info('connected');
            $rootScope.$apply(function(){
                self.state = 'connected';
                self.message = 'websocket connected';
            });
        });

        this.ws.onMessage(function(message){
            console.log("RECEIVED : " + message);
        });
    }
};

}]);

app.controller('WebSocketStateCtrl', ['$scope', 'WebSocketWrapper', function($scope, WebSocketWrapper){
    $scope.websocket = WebSocketWrapper;
    $scope.websocket.init();
    $scope.sendMsg = function sendMsg() {
        var message = textId.value;
        display("Message send : " + message);
        websocket.send(message);
        //ws.send(message);
    }
    $scope.display = function display(message) {
        var ligne = document.createElement("p");
        ligne.innerHTML = message;
        messageDiv.appendChild(ligne);
    }
}]);



</script>
</head>
<body>

<div id="messageDivId"></div>
    <a href="">ClickMe</a>

<!-- this div displays the status of the websocket connection -->
<div data-ng-controller="WebSocketStateCtrl">
   <span data-ng-bind="websocket.message"></span>
   <span class="circle" data-ng-class="{initializing: websocket.state === 'initializing', 
         connected : websocket.state === 'connected', 
         disconnected: websocket.state === 'disconnected',
         reconnecting: websocket.state === 'reconnecting'}">
   </span>

   <div style="text-align: center;">
    <form action="">
        <input id="textId" name="message" value="" type="text">&nbsp;
        <button ng-click="sendMsg()">SEND</button>
    </form>
   </div>
</div>

</body>
</html>

Server side - This works fine:

package org.example.websocket;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.OnMessage;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint("/echo")
public class DeviceWebSocketServer {

    @OnMessage
    public String echo(String message){
        System.out.println("Message reçu : " + message);
        return ThreadSafeFormatter.getDateFormatter().format(new Date()) + " " + message;
    }
}

class ThreadSafeFormatter {
    private static final ThreadLocal<SimpleDateFormat> formatter = new ThreadLocal<SimpleDateFormat>(){
        @Override
        protected SimpleDateFormat initialValue(){
            return new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
        }
    };

    public static DateFormat getDateFormatter(){
        return formatter.get();
    }
}

HTML Page Code

The html page in regular javascript which shows the server side works fine :

<!DOCTYPE html>
<html>
<head>
<title>Test WebSockets</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<script language="javascript" type="text/javascript">
    var wsUri = getRootUri() + "/WebSocketHome/echo";
    function getRootUri() {
        return "ws://"
                + (document.location.hostname == "" ? "localhost" : document.location.hostname)
                + ":"
                + (document.location.port == "" ? "8080" : document.location.port);
    }
    function init() {
        messageDiv = document.getElementById("messageDivId");
        websocket = new WebSocket(wsUri);
        websocket.onopen = function(evt) {
            onOpen(evt)
        };
        websocket.onmessage = function(evt) {
            onMessage(evt)
        };
        websocket.onerror = function(evt) {
            onError(evt)
        };
    }
    function onOpen(evt) {
        afficher("CONNECTE");
    }
    function onMessage(evt) {
        afficher("RECU : " + evt.data);
    }
    function onError(evt) {
        afficher('<span style="color: red;">ERREUR:</span> ' + evt.data);
    }
    function envoyer() {
        var message = textId.value;
        afficher("ENVOYE : " + message);
        websocket.send(message);
    }
    function afficher(message) {
        var ligne = document.createElement("p");
        ligne.innerHTML = message;
        messageDiv.appendChild(ligne);
    }
    window.addEventListener("load", init, false);
</script>
</head>
<body>
    <h2 style="text-align: center;">Client WebSocket Echo</h2>
    <div style="text-align: center;">
        <form action="">
            <input id="textId" name="message" value="" type="text">&nbsp;
            <input onclick="envoyer()" value="Envoyer" type="button">
        </form>
    </div>
    <div id="messageDivId"></div>
    <a href="http://localhost:8080/WebSocketHome/test.html">ClickMe</a>
</body>
</html>
6
  • Your service calls a display function that doesn't exist. Open your dev tools console and check for errors. Also, avoid dom manipulation and using innerHTML. Use angular as it's meant to be used: modify the model, and use the template to display what the model contains. Commented Oct 27, 2017 at 16:07
  • JB Nizet : the display function exists inside the controller : $scope.display = function display(message) {...}; maybe it is not the right place for this function ?? Commented Oct 27, 2017 at 23:53
  • Yeah, but that's really not how JavaScript works. Adding a function to the scope of a specific controller instance doesn't make it available globally for a service to call. A scope is created for each controller instance, and is meant to contain the state and functions available to that specific controller instance. A service doesn't, and can't access that scope. Commented Oct 28, 2017 at 5:10
  • JB Nizet : ok, but what is the syntax for adding the "display" function to the service ? Commented Oct 29, 2017 at 15:07
  • How do you tell ws that you would like to execute some piece of code every time there is a message? You pass a callback function, right? So, how could you tell, from your controller, to your WebSocketWrapper service, that you want to display the message every time a message is received? Commented Oct 29, 2017 at 15:12

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.