Getting data from another controller - angularjs

I have one controller.
app.controller('first',['$scope','scopeService', function ($scope,scopeService){
$scope.initialize = function()
{
scopeService.store('value', $scope);
}
}]);
My second controller is
app.controller('second',['$scope','scopeService', function ($scope,scopeService){
$scope.initialize = function()
{
scopeService.get('value', $scope);
}
}]);
But my second controller is loaded before first so i am getting value as undefined..

You can pass data between the controller in two different ways. One way is to use a service to get and store data. Then both controllers can get the data from the service itself. Services are singleton so if it stores data once in its variable then another controller can get is as well.
Another way is to use Angular events. You can emit an event from your second controller and have the first controller listen for the event.
Example code, emit event:
$scope.$emit('event-name', {data: someDate});
Then receive the event using $rootScope:
$rootScope.$on('event-name', function (event, data) {
//do something with data
});
In your case, you should emit the event when your controller receives the data. Then the first controller listening to this event will get the data as well.

Related

Angularjs $on called twice

So I have this situation where one controller is emitting the event and the other controller has the listener. Here is the code:
In controller A, I have this method:
$scope.process = function () {
var taskName = 'process';
$scope.$emit('process', taskName);
}
In controller B, I have this:
$rootScope.$on('process', function (event, taskName) {
//Do something here
});
Now whenever I visit other pages on application and comeback to this, the process listener gets created twice. I cannot use controller scope as the event is getting emitted from other controller. How can I destroy listener once it has completed its task? I have also tried $scope.$destroy(). Doesn't really work. What is the correct way of doing this?
I am on Angularjs 1.4.7.
Usually you do it in different way:
$rootScope.$broadcast(...)
...
$scope.$on(...)
Then you do not need to unsubscribe.
If you really need for some reason to subscribe to $rootScope, then:
var deregister = $scope.$on(...);
...
deregister(); // destory that listener

Call controller function from service in angularjs

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.

Cannot listen for events on Controller $scope

I am facing a race condition. One of the service is changing the view using ui-router and then broadcasting event from $rootscope. The scope of the controller(tied to the changed view) is listening on this event, but whats happening is when the view is changed my controller scope is reinitialized and till the time it is ready the event has already been dispatched.
So the new controller scope never listens for the event.
Please provide some way to handle this situation.
What you can do is, Instead of listening for event in controller, listen for the event in a service. Since, service are bound to have only a single instance, you won't face such issue in service.
And, as for as the controller, you can first check for the presence of a flag in the service, then retrieve the updated value.
Consider this sample code taken from here.
app.factory('userService', ['$rootScope', function ($rootScope) {
var service = {
model: {
name: '',
email: ''
},
SaveState: function () {
sessionStorage.userService = angular.toJson(service.model);
},
RestoreState: function () {
service.model = angular.fromJson(sessionStorage.userService);
}
}
$rootScope.$on("savestate", service.SaveState);
$rootScope.$on("restorestate", service.RestoreState);
return service;
}]);

What do I need to do to get $broadcast running?

I have been working with the excelent ngStorage plugin for angular.
When setting it up you can declare a $scope-node connected to the localstorage like this:
$scope.$store = $localStorage;
$scope.$store is now accessible in all controllers etc.
I want to remove some stuff from localstorage and access it using broadcast instead.
In my init I performed:
$scope.taskarr = [];
$rootScope.$broadcast('taskarrbroad',$scope.taskarr);
What is required in order to add, remove and $watch this array, none of the mentioned seem to work.
Here, nothing happens
controller('textController', function($scope,$routeParams){
$scope.$watch('taskarrbroad.length', function(){
console.log($scope.taskarr.map(function(task){
return task.content;
}).join('\n'));
})
})
Here I can access $scope.taskarr and update it, but the view isn't updated. $scope.$apply() didn't help either (the timeout is because it's already within a digest.
controller('stateSwitchController', function($scope, $routeParams, $timeout){
$scope.taskarr = $scope.$store[$routeParams.state].taskarr || [];
console.log($scope.taskarr);
$timeout(function() {
$scope.$apply();
})
}).
$broadcast is a way to send events to other parts of your application. When you broadcast an event, someone else has to listen to that even with $on(). Something like:
// Some controller
$rootScope.$broadcast('my-event', eventData);
// Some other controller
$scope.$on('my-event', function() {
console.log('my-event fired!')
});
$watch is something else, it's not an event listener per se, it's a way to attach a function that gets called when that value changes, and that value has to be on the scope. So your watch should look like this:
$scope.$watch('taskarr.length', function(){
});
Since you've named the array taskarr on the scope.

Safe to pass current $scope from controller to angularjs service function

Within an angular controller I am attaching to a websocket service. When the controllers scope is destroyed I obviously want to remove the subscription.
Is it safe to pass the current scope to my service subscription function so it can auto remove on scope destroy? If I dont then each controller who attaches to a socket listener has to also remember to clean up.
Basically is it safe to pass current $scope to a service function or is there a better way of doing this?
I had similar need in my project. Below is the object returned in a AngularJS factory (which initializes WebSocket). The onmessage method automatically unsubscribes a callback if you pass in its associated scope in the second argument.
io =
onmessage: (callback, scope) ->
listeners.push callback
if scope then scope.$on "$destroy", => #offmessage callback
offmessage: (callback) -> listeners.remove callback
The JavaScript equivalence is below.
var io = {
onmessage: function(callback, scope) {
var _this = this;
listeners.push(callback);
if (scope) {
scope.$on("$destroy", function() {
_this.offmessage(callback);
});
}
},
offmessage: function(callback) {
listeners.remove(callback);
}
};
I would not pass the scope. Instead, I would explicitly, in your controller, hook up the unsubscribe.
From http://odetocode.com/blogs/scott/archive/2013/07/16/angularjs-listening-for-destroy.aspx :
$scope.$on("$destroy", function() {
if (timer) {
$timeout.cancel(timer);
}
});
I think having this done explicitly is not as magical, and easier to follow the logic. I think the service would be doing too much if it were to also unsubscribe. What if a controller wants to unsubscribe early?
However, if you do have a very specific use case that's used everywhere, it would be fine to pass the scope in. The amount of time the service needs the scope is very small, basically when the controller first executes so that the service can listen to the $destroy event.

Resources