简体   繁体   中英

Errors when using socket.io in AngularJs on user updates

Hi I'm trying to make an automated update on a list of articles whenever the user changes his preferred language.

The way I'm trying to do this is by having a IO socket update whenever the user changes in the database.

However I seem to be unsuccesfull in my endeavors, and I have no idea as to why.

Since I'm new to socket.io I thought I'll ask the coding gods in here for some help.

May the software be with you ^^

PS: the project is a Angular fullstack project, scaffolded with Yeoman


Code time!


client/ components/ articlebar/ articlebar.controller.js

'use strict';

angular.module('unityAcademyApp')
.controller('ArticlebarCtrl', function ($scope, $location, Auth, socket) {
  $scope.articles = {};

  function populateArticles(){ 
       ...
        Some functionality where $scope.articles are set
        ...
    };

    socket.syncUpdates('user', $scope.articles, function() {
        console.log('hit');
        populateArticles();
    });
});


client/ components/ socket/ socket.service.js

/* global io */
'use strict';

angular.module('unityAcademyApp')
  .factory('socket', function(socketFactory) {

    // socket.io now auto-configures its connection when we ommit a connection url
    var ioSocket = io('', {
      // Send auth token on connection, you will need to DI the Auth service above
      // 'query': 'token=' + Auth.getToken()
      path: '/socket.io-client'
    });

    var socket = socketFactory({
      ioSocket: ioSocket
    });

    return {
      socket: socket,

      /**
       * Register listeners to sync an array with updates on a model
       *
       * Takes the array we want to sync, the model name that socket updates are sent from,
       * and an optional callback function after new items are updated.
       *
       * @param {String} modelName
       * @param {Array} array
       * @param {Function} cb
       */
      syncUpdates: function (modelName, array, cb) {
        cb = cb || angular.noop;

        /**
         * Syncs item creation/updates on 'model:save'
         */
        socket.on(modelName + ':save', function (item) {
          var oldItem = _.find(array, {_id: item._id});
          var index = array.indexOf(oldItem);   // this is line 39
          var event = 'created';

          // replace oldItem if it exists
          // otherwise just add item to the collection
          if (oldItem) {
            array.splice(index, 1, item);
            event = 'updated';
          } else {
            array.push(item);
          }

          cb(event, item, array);
        });

        /**
         * Syncs removed items on 'model:remove'
         */
        socket.on(modelName + ':remove', function (item) {
          var event = 'deleted';
          _.remove(array, {_id: item._id});
          cb(event, item, array);
        });
      },

      /**
       * Removes listeners for a models updates on the socket
       *
       * @param modelName
       */
      unsyncUpdates: function (modelName) {
        socket.removeAllListeners(modelName + ':save');
        socket.removeAllListeners(modelName + ':remove');
      }
    };
  });


server/ config/ socketio.js

/**
 * Socket.io configuration
 */

'use strict';

var config = require('./environment');

// When the user disconnects.. perform this
function onDisconnect(socket) {}

// When the user connects.. perform this
function onConnect(socket) {
    // When the client emits 'info', this listens and executes
    socket.on('info', function (data) {
        console.info('[%s] %s', socket.address, JSON.stringify(data, null, 2));
    });

    // Insert sockets below
    require('../api/translation/translation.socket').register(socket);
    require('../api/comment/comment.socket').register(socket);
    require('../api/article/article.socket').register(socket);
    require('../api/language/language.socket').register(socket);
    require('../api/thing/thing.socket').register(socket);
    require('../api/user/user.socket').register(socket);
}

module.exports = function (socketio) {
    // socket.io (v1.x.x) is powered by debug.
    // In order to see all the debug output, set DEBUG (in server/config/local.env.js) to including the desired scope.
    //
    // ex: DEBUG: "http*,socket.io:socket"

    // We can authenticate socket.io users and access their token through socket.handshake.decoded_token
    //
    // 1. You will need to send the token in `client/components/socket/socket.service.js`
    //
    // 2. Require authentication here:
    // socketio.use(require('socketio-jwt').authorize({
    //   secret: config.secrets.session,
    //   handshake: true
    // }));

    socketio.on('connection', function (socket) {
        socket.address = socket.handshake.address !== null ?
            socket.handshake.address.address + ':' + socket.handshake.address.port :
            process.env.DOMAIN;

        socket.connectedAt = new Date();

        // Call onDisconnect.
        socket.on('disconnect', function () {
            onDisconnect(socket);
            console.info('[%s] DISCONNECTED', socket.address);
        });

        // Call onConnect.
        onConnect(socket);
        console.info('[%s] CONNECTED', socket.address);
    });
};


server/ api/ user/ user.socket.js

/** * Broadcast updates to client when the model changes */

'use strict';

var User = require('./user.model');

exports.register = function(socket) {
  User.schema.post('save', function (doc) {
    onSave(socket, doc);
  });
  User.schema.post('remove', function (doc) {
    onRemove(socket, doc);
  });
}

function onSave(socket, doc, cb) {
  socket.emit('user:save', doc);
}

function onRemove(socket, doc, cb) {
  socket.emit('user:remove', doc);
}

Errors encountered so far

So far I get the following error when running the code

TypeError: array.indexOf is not a function
    at Socket.<anonymous> (socket.service.js:39)
    at socket.js:24
    at angular.js:17782
    at completeOutstandingRequest (angular.js:5490)
    at angular.js:5762
        (anonymous function)        @ angular.js:12416
        $get                        @ angular.js:9203
        (anonymous function)        @ angular.js:17785
        completeOutstandingRequest  @ angular.js:5490
        (anonymous function)        @ angular.js:5762

I'm not sure why you get that error, but I think I know why your data isn't updating.

You have to wrap your callback functions inside a $timeout function in order to trigger your changes. For example, you could do this:

$timeout(function(){
    cb(event, item, array);
}, 0);

Remember to include $timeout directive in your socket factory.

what's 'undescore' mean? I'm not sure about the 'undescore', but I guess that's alias for 'this'. I think you should init var _ = this.

I just guessing.

I found the problem.

The error where due to it looking for a user in a list of articles, which returned undefined due to there not being any match. The solution was therefore to change the code in client/ components/ articlebar/ articlebar.controller.js

from

socket.syncUpdates('user', $scope.articles, function() {
    console.log('hit');
    populateArticles();
});

to

socket.syncUpdates('user', $scope.users, function() {
    console.log('hit');
    populateArticles();
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM