Reputation: 4014
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
Upvotes: 0
Views: 610
Reputation: 4014
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();
});
Upvotes: 0
Reputation: 3038
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.
Upvotes: 1
Reputation: 1
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.
Upvotes: 0