How to send data from child controller to Parent controller in AngularJS? - javascript

I need some guidance to take the best practice for my task in AngularJS.
Task:
Inside the view : I have one parent controller and two child controllers.
Child controllers work with their own $scope and objects.
When I press save in the view, I need to get the data from child controllers to parent controller in order to prepare an object for posting it to the server.
I am getting confused of what is the best solution for this approach.

A common way of sharing data between controllers is to use use a service.
You could also broadcast updates to the parent controller

There are many different ways to achieve this..
Using $rootScope.
Using Services
Use broadcast and emit
Declare an object in parent controller and then modify the same object in the child controller.
Using $rootScope is not a good approach, as the $rootScope variable is destroyed when application is closed.
I will also not recommend broadCast or emit, until it's required.
Services, is good for communication b/w controllers, but again you have inject it and modify the methods.
In your, scenario, i would recommend to use the common $scope object variable, which is declared inside parent and used in child controllers, as all methods are inherited in the child controllers.

Above answers are useful, but below is an simple way to update a $scope object in parent controller from child scope as below.
In child controller, $scope.$parent.parentObject = updatedObject
Hope it helps!

There are three common ways to share data between controllers:
1 put data in service or factory. Since they are singleton, any controller injected with same service can share the data within that service
2 put data in $rootScope
3 use $broadcast or $emit to send events between scopes, and pass the shared data as event arguments

Related

When to use emit and broadcast in Angular JS?

I have been playing with Angular for 1 month and every time I thought It would make sense to use emit and broadcast to communicate between different parts of the framework I found articles stating that we should avoid them if we can (for instance: http://seanhess.github.io/2013/10/14/angularjs-directive-design.html)
So far I focused on communication between directive and controller, and between controller and service:
Directive <--> Controller: To call controller's methods from directive I use isolated scope and callback. In the other direction I use state variables in the controller that are watched in the directive and when modified trigger directive's methods .
Controller <--> Service: same mechanism. I use service's methods directly in my controller (this is the classic usage of service) and state variables in the service that are watched in the controller.
My question is straightforward: could you give me examples and explanations when emit and broadcast are relevant ?
When you need to send a message or a request from inner scope to outer scope you can use $emit and when you want to do same from outer scope to inner scope we use $broadcast.

garbage collecting variables in angularjs service

I am new to angularjs. I have designed an angularJS service, which is as per the diagram given below :-
Global Service is used as a mean for inter-controller communication. That's, it contains data shared between parent and child controller. Grand Parent controller opens a popup dialog which has parentController2, which in turn open another popup, which has childController3.
Now, What I want is, data stored in global service must be set to null, when its associated controller is destroyed. It's because services are singleton in angularjs, as per my knowledge. So, I don't want service to hold variable throughout the life-cycle of application, even if they are not required.
Moreover, I am using controllerAs syntax and don't want to use $scope(I know that I can do garbage collection in '$destroy' event on scope), to make my stuff compatible with angularjs 2.0.
Is there any way, I can garbage collect variable in service, which are not required, from controller, when controllerAs syntax is used ?
Apologizing for newbie question. Thanks in advance.
using ng-view is one more solution over here for garbage collection as it destroy's the scope as soon as view is changed. It will be used with ngroute but still provides better mechanism for garbage collection.
You can check the ng-view code
function destroyLastScope() {
if (lastScope) {
lastScope.$destroy();
lastScope = null;
}
}
This function is called inside the directive that destroys the scope of the previous scope i.e if you go from parent to child the parent scope will be destroyed

AngularJS - Similar view - Should i use same view with multiple controllers?

Let's say we are implementing CRUD operations for a specific object - those view would be very similiar and i think i should use the same view with multiple controllers. Is there a way to choose the controller dinamicaly based on a parameter or this type of action can be only taken inside the controller?
You technically can, but according to the exellent angular styleguide from Johnpapa, style Y037 :
Define a controller for a view, and try not to reuse the controller
for other views.
Though, you're actually right thinking that some CRUD logic should be made common and abstracted. Controllers are just not the right place; Factories (ie services) are.
You can use the same view on different controllers but it depends on what you are doing inside the view and whether or not the controller has the necessary members within the $scope object that are bound in the view. You can add an "action" variable on your $scope object and modify the view based on the same.

$emit, $broadcast, prototypical inheritance

Still on the basics of AngularJS, i understand the concepts, however, just looking at custom events,
$emit
and
$broadcast
for nested controller..
According to the docs, $emit bubbles the event, ie. passes it up the chain, for nested controllers,
My question, is, how is this different to just simply calling a function from the parent controller (prototypical inheritance). Or have i miss understood something?
The thing is, you can't always be certain that your direct parent, is the one you want to call. It's easy to break your code with that kind of anti-pattern.
And you must agree that
$scope.$parent.$parent.$parent.doSomething();
Is pretty ugly.
Instead you can $emit an event upwards, now it doesn't matter how far up the chain your parent controller is, as long as it is listening and reacting.
This gives you nice loose coupling between controllers, and just acts like a message pump.
The same goes for $broadcast, just downwards instead, and here I would argue that it is even more important.
Take the example of a child controller with many parents or a parent controller with many children. Should the developer need to maintain a list of children within the parent to invoke a function on each of them. $emit and $broadcast are utilities to allow a loose-coupling messaging along the lines of an Observer pattern. If all parents in the hierarchy need to know that a child controller has done some task or needs some task dome on its behalf then is can just generate an event and interested parties can listen.
Data can also be passed removing the need for controllers to share data on the inherited scope.
$emit helps you to pass event to the parent controllers.
You can't use $controller('ParentController', {scope: scope}) in all your child controllers to inherit the properties. To make the code clean and loosely coupled, $emit will help you to achieve that.
Assume you have three levels of hierarchy and you want the child controller to update the value of a particular parent controller. If you are going to do that via prototype chain, you need to inherit that particular controller using $controller('ParentController', {scope: scope}) but $emit will avoid that. You need not know which parent controller. instead just emit the event.
In the appropriate parent controller where you want to read the data, use
$scope.$on("eventname", function(event, data) {
// update value here
});

Angularjs Can I change $scope value of a controller from another controller?

I have an HTML div , like
<div id="loader-container" data-ng-controller="LoaderController" ng-show="shouldShow">
Some html design
</div>
And in my controller
angular.module('core').controller('LoaderController', ['$scope','$location', 'Authentication', '$rootScope',
function($scope,$location, Authentication, $rootScope) {
$scope.shouldShow = true;
}
]);
And now, I want to hide that html div from another controller, That's why I tried to make $scope.shouldShow variable as false from another controller. So how can I make
$scope.shouldShow = false;
from another controller. Is it possible or any alternative way.?
every controller will create a new Scope.
Hence the changing the scope in one controller will not reflect in the scope of other controller.
If you want to share a property across the controllers create that variable on the $rootScope and use it.
In Controller
$scope.$root.shouldShow = true; //or false
In Markup
<div ng-show="$root.shouldShow"></div>
It's not a good idea to manipulate a $scope of a controller from a different controller directly. It would make your controllers very tightly coupled.
One commonly accepted way to communicate between controllers is through messages using the publish-subscribe pattern.
If your controllers are in completely separate components and you just need to notify the other controller, you can use the $broadcast/$emit and $on methods of the scope object to broadcast a message from one controller and listening to a specific message in a different controller. When an action happens that should change the shouldShow variable, you can just broadcast a message and make the other controller listen and act on it.
Root Scope API
Another common way to communicate between controllers is by using angular services, acting as a mediator between controllers.
If your controllers are part of the same component/module, and you need to share state/behavior between those, then using an angular service to encapsulate that logic and expose it would be an OK approach (services are singletons in Angular). That would be pretty simple to implement.
However, not knowing more details about your exact requirements, it's hard to design a proper solution.
Thanks to #Callum Linington for discussing the alternatives in the comments.

Categories

Resources