change scope value in already loaded controller from another controller without rootScope - angularjs

I need to update one $scope value of controller-2(already loaded) from controller-1. I don't want to use $rootScope.
Can I use broadcast or emit for same?

If the controllers are in a child-parent relationship, you can use:
$emit (if controller1 is child of controller2)
$broadcast (if controller2 is child of controller1)
If they are not in this relationship, then you need to:
emit from controller1
catch the event in the closest parent (could be the app)
broadcast new event from this parent
catch the event in controller2
Of course... this is not always the best way to go.
If you prefer, you can use other ways to communicate (e.g. use a common service).

Use brodcast on rootscope and listen on scope.
The best practice is to create a service for each custom event you want to listen to or broadcast.
.service("hiEventService",function($rootScope,$scope) {
this.broadcast = function() {$rootScope.$broadcast("hi")}
this.listen = function(callback) {$scope.$on("hi",callback)}
})

You can use $localStorage for change that value. or create one service for get and set that value.

Related

angular controllerAs(this) equivalent of $scope.$broadcast and $scope.on,

According to this answer I just want fire event from controller to another
Call a method of a controller from another controller using 'scope' in AngularJS
$scope.$on("myEvent", function (event, args) {
$scope.rest_id = args.username;
$scope.getMainCategories();
});
And in the second controller you'd just do
$scope.initRestId = function(){
$scope.$broadcast("myEvent", {username: $scope.user.username });
};
But I don't use $scope in my application, just controllerAs and this. There is a way to fire event without inject the scope ? Or should I inject $scope anyway ?But I read in another answer that using both scope and controllerAs is bad practice.
It's not possible to register an $emit or $broadcast event without $scope or $rootScope being injected in the controller.
It is indeed bad practice to use $scope variables and functions since the instance of your controller is already injected inside the $scope with the controllerAs syntax.
But there is not other choice than injecting scope objects if you want to use these events.
However you shouldn't use $emit or $broadcast events just to share data. These events are used for application wide information (like user has logged in or logged out...etc.)
A good practice when using angular events is to prefer $rootScope.$emit because $scope relies on the hierarchy of your components.
For example:
$scope.$emit will emit to the parent component.
$scope.$broadcast will broadcast to children components.
Then $rootScope.$broadcast will broadcast events to the rootScope as well as the scope (which may make your code messy real quick)
$rootScope.$emit is to be preferred as it registers the event application wide and makes it available to the rootScope only. ($rootScope.$on)
Another good practice is to unbind your custom events.
Whenever a component or directive is unloaded/destroyed, the event listener will still reside inside rootScope resulting in possible memory leaks.
To unbind an event:
var unbind = $rootScope.$on('logout', function(event, data) {
console.log('LOGOUT', data);
});
$scope.$on('$destroy', unbind);
I think that generally overuse of $broadcast and $emit is a bad practice too. If you don't want to use the $scope, why not moving the logic handled by events to a service?

Angularjs $rootScope.$broadcast when watch position to pass message from factory to directive

I want to create factory which will navigator.geolocation.watchPosition and everytime will broadcast to rootscope then directive will listen $scope.$on. Is there any performance issue on the way or better how way to do it? The device with this app will be on the always on the move.
Broadcast is always heavy.
Instead of broadcast, emit on the rootScope and listen on the rootScope. And when your directive scope is destroyed remove the listener from the scope.
Factory:
$rootScope.$emit('eventName:emit');
Directive:
var destroyFn = $rootScope.$on('eventName:emit', listernFn);
$scope.$on('$destroy', destroyFn);
Changed name eventname to eventname:emit to make event specific to listen $emit event.

Broadcast rootscope change

I'm trying to write a script to access the rootscope and change a variables value from the dev tools. I can get the scope and the rootscope, but my changes don't show up in my bindings. However if I use a bound input everything is fine.
Example:
<input ng-model="mode"></input>
<span ng-bind-html="mode"></span>
update each other fine but
angular.element("body").scope().$root.mode = 'test'
Updates the controller but has no effect on the bindings. I have compared my original controller and my console controller using === and they are equal.
So from what I read I need to broadcast or emit that I've changed the scope, however I can't seem to figure out what to broadcast , or if I am broadcasting correctly.
Broadcast code attempts:
scope.$apply(function() {root.$emit('change', {mode: 1})})
scope.$apply(function() {root.$emit('stateChangeSuccess', {mode: 1})})
root.$apply(function() {root.$emit('change', {mode: 1})})
root.$apply(function() {root.$emit('stateChangeSuccess', {mode: 1})})
Additionally it should be noted that changing the input will change the span but not my copy of the root scope.
root.mode = 'console'
type 'input text' in the input
root.mode returns 'console'
I don't think this is possible with events (perhaps I'm wrong). There is another way to do make changes from the console though.
The reason angular.element("body").scope().$root.mode = 'test' doesn't update your bindings is that Angular doesn't "know" that a change to the scope has been made. If you are making updates to your data model from "outside" the Angular world, you will need to wrap you changes in an $apply() function:
var $rootScope = angular.element("body").scope().$root;
$rootScope.$apply(function() {
$rootScope.mode = 'hi';
});
FYI, when sending an event from the $rooteScope, you'll want to use $broadcast instead of $emit. $broadcast broadcasts an event "downward" to all descendant scopes, while $emit sends the event "upwards" to ancestor scopes. If you $emit from the $rootScope, there are no ancestor scopes to pick up the event (though perhaps the $rootScope will?).
If I understand you correctly, scope() === $root, otherwise you're making some false assumptions here.
WHat I believe is happening is that you are changing value of root scope but your bindings are actually using another scope due to prototype inheritance(eg the string property is actually created in scope() when you bind against it).
Try either of these two tricks:
1) Either try scope.$apply(function(){scope.mode ='test'});
2) $root.mode={name:'test'}; and bind against mode.name in html
Notice that you should be able to fire a $digest cycle using $apply on root scope and it should propagate down to child scopes too. $root.$apply();

Why do we use $rootScope.$broadcast in AngularJS?

Tried to find some basic information for AngularJS $rootScope.$broadcast, But the AngularJS documentation doesn't help much. In easy words why do we use this?
Also, inside John Papa's Hot Towel template there is a custom function in the common module named $broadcast:
function $broadcast() {
return $rootScope.$broadcast.apply($rootScope, arguments);
}
I did not understand what this is doing. So here are couple of basic questions:
1) What does $rootScope.$broadcast do?
2) What is the difference between $rootScope.$broadcast and $rootScope.$broadcast.apply?
$rootScope basically functions as an event listener and dispatcher.
To answer the question of how it is used, it used in conjunction with rootScope.$on;
$rootScope.$broadcast("hi");
$rootScope.$on("hi", function(){
//do something
});
However, it is a bad practice to use $rootScope as your own app's general event service, since you will quickly end up in a situation where every app depends on $rootScope, and you do not know what components are listening to what events.
The best practice is to create a service for each custom event you want to listen to or broadcast.
.service("hiEventService",function($rootScope) {
this.broadcast = function() {$rootScope.$broadcast("hi")}
this.listen = function(callback) {$rootScope.$on("hi",callback)}
})
What does $rootScope.$broadcast do?
$rootScope.$broadcast is sending an event through the application scope.
Any children scope of that app can catch it using a simple: $scope.$on().
It is especially useful to send events when you want to reach a scope that is not a direct parent (A branch of a parent for example)
!!! One thing to not do however is to use $rootScope.$on from a controller. $rootScope is the application, when your controller is destroyed that event listener will still exist, and when your controller will be created again, it will just pile up more event listeners. (So one broadcast will be caught multiple times). Use $scope.$on() instead, and the listeners will also get destroyed.
What is the difference between $rootScope.$broadcast & $rootScope.$broadcast.apply?
Sometimes you have to use apply(), especially when working with directives and other JS libraries. However since I don't know that code base, I wouldn't be able to tell if that's the case here.
$rootScope.$broadcast is a convenient way to raise a "global" event which all child scopes can listen for. You only need to use $rootScope to broadcast the message, since all the descendant scopes can listen for it.
The root scope broadcasts the event:
$rootScope.$broadcast("myEvent");
Any child Scope can listen for the event:
$scope.$on("myEvent",function () {console.log('my event occurred');} );
Why we use $rootScope.$broadcast? You can use $watch to listen for variable changes and execute functions when the variable state changes. However, in some cases, you simply want to raise an event that other parts of the application can listen for, regardless of any change in scope variable state. This is when $broadcast is helpful.
Passing data !!!
I wonder why no one mention that $broadcast accept a parameter where you can pass an Object
Example:
// the object to transfert
var obj = {
status : 10
}
$rootScope.$broadcast('status_updated', obj);
$scope.$on('status_updated', function(event, obj){
console.log(obj.status); // 10
})
What does $rootScope.$broadcast do?
It broadcasts the message to respective listeners all over the angular app, a very powerful means to transfer messages to scopes at different hierarchical level(be it parent , child or siblings)
Similarly, we have $rootScope.$emit, the only difference is the former is also caught by $scope.$on while the latter is caught by only $rootScope.$on .
refer for examples :- http://toddmotto.com/all-about-angulars-emit-broadcast-on-publish-subscribing/

Common Controller for ng-view

Is there a way to call a common controller everytime ng-view is changed? i.e i want a common controller to be called everytime a new $route is loaded.
If you have specified custom controllers for your different routes, then there's no way that I know of that you can also specify a common controller that always gets invoked, unless you use some kind of inheritance and always call a method in the base controller.
An alternative approach is to subscribe to the events the route service broadcasts.
Example:
function MyController($rootScope, [...]) {
$rootScope.$on('$routeChangeSuccess', function (current, previous) {
// ...
});
}
You have a list of available events and their parameters here.
I believe you also can add properties, methods etc. to $rootScope which you can use in bindings in your views thanks to how Angular's binding mechanism works. If it doesn't find it on the current scope, it checks its parent etc. up to the root scope.

Resources