How do I run a function when socket.io updates a variable. It seems that $watch does not work or purhaps I am doing something wrong.
$http.get('/api/availabilitys/' + myId).then(response => {
$scope.availability = response.data;
socket.syncUpdates('availability', $scope.availability);
});
$scope.$watch('availability', function() {
console.log('test'); //This is not printing on update
angular.forEach(self.location, function (loc){
loc.availability = $scope.availability.filter(function (a){
return a.loc === loc._id;
});
});
});
The functions have to be in the same controller / scope because of encapsulation. The $scope of angular does not know if socket.io updates a variable, use a socket.on() listener to trigger the angular $watch
Try the code in this thread Socket.IO message doesn't update Angular variable
Instead of $watch in angular you can use socket.on() of socket.io
var container = angular.module("AdminApp", []);
container.controller("StatsController", function($scope) {
var socket = io.connect();
socket.on('message', function (msg) {
console.log(msg);
$scope.$apply(function() { $scope.frontEnd = msg; });
});
});
See (the posts at the end of) this thread
How do I use $scope.$watch and $scope.$apply in AngularJS?
Related
In my AngularJS application, I have a controller-A and a factory. I am using the following code in factory to call the function in controller-A. In the initial call, the function in controller A's function executes 1 time; on the next call the controller-A's function executes 2 times. Hence the number of times executed get increased for each call. Is it possible to avoid this, please advise me. I have added the factory code and controller-A code below:
Factory code:
updateUserData: function (value, action) {
$("#myModalInsertUser").modal('hide');
var id = value.Id;
var params = {};
params.id = depotId;
$rootScope.selectedId = params;
$rootScope.$emit("EVENT_1", {id});
});
Controller-A code:
var listener = $rootScope.$on("EVENT_1", function(event, params, reload) {
$scope.confirmUserInfo(params);
});
$scope.confirmUserInfo = function(params) {
$('#myModalConfirmUser').modal('show');
$('#closeConfirmUser').unbind('click').click(function () {
$('#myModalConfirmUser').modal('hide');
var params = $rootScope.selectedId;
$scope.getUsers(params);
$scope.$on('$destroy', listener);
});
}
Attach the event listener to $scope and it will be automatically destroyed when the scope is destroyed:
̶v̶a̶r̶ ̶l̶i̶s̶t̶e̶n̶e̶r̶ ̶=̶ ̶$̶r̶o̶o̶t̶S̶c̶o̶p̶e̶.̶$̶o̶n̶(̶"̶E̶V̶E̶N̶T̶_̶1̶"̶,̶ ̶f̶u̶n̶c̶t̶i̶o̶n̶(̶e̶v̶e̶n̶t̶,̶ ̶p̶a̶r̶a̶m̶s̶,̶ ̶r̶e̶l̶o̶a̶d̶)̶ ̶{̶
var deregisterFn = $scope.$on("EVENT_1", function(event, params, reload) {
$scope.confirmUserInfo(params);
});
$scope.confirmUserInfo = function(params) {
$('#myModalConfirmUser').modal('show');
$('#closeConfirmUser').unbind('click').click(function () {
$('#myModalConfirmUser').modal('hide');
var params = $rootScope.selectedId;
$scope.getUsers(params);
̶$̶s̶c̶o̶p̶e̶.̶$̶o̶n̶(̶'̶$̶d̶e̶s̶t̶r̶o̶y̶'̶,̶ ̶l̶i̶s̶t̶e̶n̶e̶r̶)̶;̶
});
}
The recommended practice is to broadcast events from $rootScope and receive them on the $scope interested in the event.
is it possible to destroy the listener before the scope gets destroyed?
To remove the listener, simply invoke the de-register function:
deregisterFn();
hi all i am using angulrajs passing one value from one controller to another controller using service it's work fine but my need is when service value change in controller 2 i get the service value in one scope when scope value change i need trigger the function it's called refresh function when service value change and that i need to call the refresh function here my fiddle
https://jsfiddle.net/ctawL4t3/10/
You can just $watch your value.storeObject. Though it's not best of the practices, but it suits this kind of feature.
$scope.$watch('value.storedObject', function(newVal) {
if(newVal !== '') {
refresh()
}
})
working fiddle (open console to see refresh function logging)
You can try to use angular default $emit, $broadcast, or try to do 2 simple functions in own service
angular.module('app').factory('StoreService', function() {
var listeners = {};
var emit = function(name, val) {
if(listeners[name]) {
listeners[name](val)
}
}
var on = function(name, callback) {
listeners[name] = callback;
}
return {
emit: emit,
on: on,
storedObject: ''
};
});
JSFiddle example
JSFiddle example $watch
JSFiddle example ng-change is better because, you can use easily debounce
you can use broadcast function for that
Please check this SO link to find the related answer
How to call a function from another controller in angularjs?
app.controller('One', ['$scope', '$rootScope'
function($scope) {
$rootScope.$on("CallParentMethod", function(){
$scope.parentmethod();
});
$scope.parentmethod = function() {
// task
}
}
]);
app.controller('two', ['$scope', '$rootScope'
function($scope) {
$scope.childmethod = function() {
$rootScope.$emit("CallParentMethod", {});
}
}
]);
I am using socket.io to enable chat in my app and i am using a service SocketService to perform all the socket stuff. When a message came then i want to trigger a function of a controller from the service SocketService to make some changes in the UI.
So i want to know that how can i access the function of a controller from the service.
Sample Code:
.service('SocketService', function ($http,$rootScope,$q) {
this.connect = function(){
var socket = io();
socket.on('connect',function(){
// Call a function named 'someFunction' in controller 'ChatController'
});
}
});
This is the sample code for service.
Now the code for controller
.controller('ChatController',function('SocketService',$scope){
$scope.someFunction = function(){
// Some Code Here
}
});
You could achieve this by using angular events $broadcast or $emit.
In your case $broadcast would be helpful,
You need to broadcast your event in $rootscope that can be listen by all the child scopes which has $on with same event name.
CODE
.service('SocketService', function($http, $rootScope, $q) {
this.connect = function() {
var socket = io();
socket.on('connect', function() {
// Call a function named 'someFunction' in controller 'ChatController'
$rootScope.$broadcast('eventFired', {
data: 'something'
});
});
}
});
.controller('ChatController', function('SocketService', $scope) {
$scope.someFunction = function() {
// Some Code Here
}
$scope.$on('eventFired', function(event, data) {
$scope.someFunction();
})
});
Hope this could help you, Thanks.
I know this is an old question, but I have another option. I have a personal bias against $broadcast - it just doesn't feel very 'angularish', I prefer making explicit calls in my code.
So instead of broadcasting to the controller and triggering another digest cycle, I prefer to have the controller register itself to the service, as below. Just be careful not to introduce any circular dependencies if the controller makes use of the same service. This works best with the controllerAs syntax, so that the calling service does not need to care about $scope.
Yes, this is more code than $broadcast, but it does give the service total access to the entire controller - all of it's methods and properties.
.service('SocketService', function ($http,$rootScope,$q) {
var _this = this;
this.chatController = null;
this.registerCtrlr = function (ctrlr) {
_this.chatController = ctrlr;
};
this.unRegisterCtrlr = function () {
_this.chatController = null;
};
this.connect = function(){
var socket = io();
socket.on('connect',function(){
// Call chatController.someFunction if chatController exists
if (_this.chatController) {
_this.chatController.someFunction();
}
});
};
});
.controller('ChatController',['SocketService', '$scope', function(SocketService, $scope){
SocketService.registerCtrlr(this);
//-- make sure controller unregisters itself when destroyed - need $scope for this
$scope.$on('$destroy', function () {
SocketService.unRegisterCtrlr();
});
this.someFunction = function(){
// Some Code Here
}
}]);
I realize this post is old but I'd like to give my two cents after dealing with Angular JS for several years. I personally would reconsider this approach. Ideally with AngularJS you'd modify your controller/directive to facilitate transferring data to the view model and ultimately bind an HTML template to what I call "the user friendly" view model. This view model should simply reflect what you want the user to see and when in general. Using this method the moment connect event happens your view model which should be bound to the service's data will reflect changes to the data the moment the data arrives.
I have successfully implemented the chatroom in angularjs using node + socket.io
But hope you guys can help me, I am stuck in a situation where I listen to the socket on the clientside
socket.on('new message', function(data){
$scope.messages.push(data);//then run ng-repeat in the template
});
Problem is,
1) if I put the above method inside the controller, the above get reinitialized(multiple listener binds) whenever I open that page again and again(We have multi page app)
or
2) if I put the above method (as the docs says) at a global place I lose the scope of the controller so I cant bind the latest model to the template
Any help??
You could try disconnecting the socket when the $scope is destroyed...
$scope.$on('$destroy', function(){
socket.disconnect();
});
But I like the service based approach...
var SocketService = function(){
var _messages = [];
socket = connectMeToSomeSocket();
socket.on('new message', function(data){
_messages.push(data);
});
Object.defineProperty(this, 'messages', {
get: function(){
return _messages;
}
})
};
Then inject the socketService in your controllers...
angular.controller('SomeCtrl',['$scope', 'socketService', function($scope, socketService){
$scope.socket = socketService;
}])
And use socket.messages in your template...
<li ng-repeat="msg in socket.messages">
If you don't like giving your templates access to the socketService or you don't like Object.defineProperty, then you can add a bindScope method your service...
this.bindScope = function($scope){
var stopWatching = $scope.$watchCollection(function(){ return _messages;}, function(){
$scope.messages = _messages;
});
// may not be necessary as `Scope` prob cleans up after itself
$scope.$on('$destroy', stopWatching);
};
And use it in your controllers...
socketService.bindScope($scope);
how do you bootstrap a controller that loaded asynchronously via require.js?
if I have something like that:
$routeProvider.when('/',
{
templateUrl:'view1.html',
controller:'ctrl',
resolve:{
load:function($q){
var dfrd = $q.defer();
require(['view1-script'],function(){
dfrd.resolve();
})
return dfrd.promise;
}
}
})
why angular still won't find the controller? I am resolving the route after it loads the script
check out this plunkr
try calling $controllerProvider.register to create your controller. I would also call $apply() on the $rootScope after resolving the deferred because without it, the view does not seem to appear:
load: function($q, $rootScope){
var dfrd = $q.defer();
require(['view1'],function(){
dfrd.resolve();
$rootScope.$apply();
})
return dfrd.promise;
}
http://plnkr.co/edit/fe2Q3BhxPYnPmeiOORHP
in addition, here is a good post: http://weblogs.asp.net/dwahlin/archive/2013/05/22/dynamically-loading-controllers-and-views-with-angularjs-and-requirejs.aspx
It's been 3 years, but just in case anyone still interested, a few months ago I wrote a post about a similar technique to do it.
The most important part is that second parameter of the method $routeProvider.when(route, ctrl) method can handle promises, so you can simply emulate it:
function controllerFactory(ctrl) {
return {
then: function (done) {
var self = this;
require(['./controller/' + ctrl], function (ctrl) {
self.controller = ctrl;
self.resolve = ctrl.resolve;
self.templateUrl = ctrl.templateUrl;
done();
});
}
};
}
And you can end up writing your route definition like this:
$routeProvider.
when('/some/route', controllerFactory('some/route')).
when('/other/route', controllerFactory('other/route'))