sharing data between two controllers which keeps on updating - angularjs

I want to share data between two controllers using some factory method. The controller Ctrl1 belongs to the first DIV tag from which HTTP request is sent and data from server is received in streaming fashion. And in other DIV tag, I want to display that result as a list (ng-repeat) which keeps on updating as the HTTP result in first DIV gets updated (also, second DIV tag starts displaying results as soon as first DIV tag gets first response, and first DIV disappears). I know how to pass data between controllers one time (e.g. ng-click="pass()"), but not sure how to achieve this. I am looking for an answer which does not uses $rootScope.

You should create a service to contain the data, then inject the service in to each controller.
For example, lets define a 'myService' service with one property 'foo' equalling a string 'bar':
angular.module('myModule').service('myService', function() {
this.foo = 'bar';
});
We can now use this in a controller as so:
angular.module('myModule').controller('MyCtrl', function($scope, myService) {
$scope.myService = myService;
});
This is now accessible in the template as {{myService.foo}} or ng-model="myService.foo" as usual.
You can then use it in a second controller in a similar way, when you update the property 'foo' in either controller the changes will persist between controllers. This is because services in angular are singletons. What you're doing by defining a service like this is creating a singleton 'myService' which can be injected wherever you want and will always be instantiated only once.
If you need to watch for changes within the controller code, you can use $scope.$watch() as usual on myService.foo.

Related

AngularJS - Sharing data from a parent route controller to all child directives on the page

I have a page that has multiple components and I've created each component as a directive. When the page is first loaded, that's when I grab all the data that should be available on the page. So all of the data exists on the controller for that route, which we'll just call pageCtrl. And then what I've been doing is binding any required data to each directive through the attributes, which of course ends up creating an isolate scope for each of them.
I know there are a few ways to share data, so given this situation, is there a recommended way of doing it? Or has anyone had better success doing it one particular way? While it's working perfectly fine the way I'm doing it, I've run into a few caveats. If I need just even one bit of information from the pageCtrl, I need to add another attribute to the directive. So it ends up creating more code on the directive element itself.
I was thinking about just creating a service that would store all the data, which the pageCtrl could initialize, instead of setting it on itself. Any feedback would be appreciated.
good question :)
First solution is to create in parent controller object and pass this object (via ng-model) to all directives. This object will be passed by reference (not by value) so controller and all directives will have access to the same object.
```
// in controller
$scope.shared_data = {someItems: []};
// in html
<my-directive ng-model=shared_data></my-directive>
Second solution is to create some simple service to store all of those data.
// in this solution you have to inject additional service to directive controller
(extended idea of point 2) creating service/factory that will be responsible by collecting and returning data. This service could be injected into directive and use the same methods to collect data. To avoid making multiple calls to API (REST) it could have some cache for each sensitive method.
Communication via events.... (probably the worsts solution for your example)
The first two ideas are probably the best, I do not know full specification of your product so final solution picking belongs to You:).
My advice is to try/play with all of those methods to really understand what is going on and how and when to use each of them :)
You can directly call your parent controller from child directive controller by using $parent.
App.controller('aCtrl', ['$scope', function ($scope) {
$scope.refresh=function(){
.......... //Updated Data get from DB
};
...........
}]);
App.directive('bDirective',function(){
restrict: 'EC',
replace: true,
scope: {},
controller: function($scope) {
$scope.$parent.refresh();
}
...
});
HTML:
<div ng-controller="aCtrl">
<div class="bDirective"></div> //directive
</div>

Pass a variable from controllers

I am programing in Angularjs, and have have a page that is divided into 3 teplates which one has an html file and js file.
The js file of which template is characterized for having the controller of the html of that template.
At the end i want to pass a variable from a certain controller to another how can i do that once they are in different controllers. Thanks
Mr.Avraam Mavridis, here is some code:
Basically down here is the controller that i want to get the value of the parameter (clientPosition) to pass it to another controller:
crm.controller("clientsModule", ["$scope", "$http", function ($scope, $http {
$scope.changeTemplate = function (index, clientPosition) {
$scope.panelTemplate = index;
$scope.clientPosition = clientPosition;
};
}]);
There are various ways you can achieve this. The easiest way to do this is using a broadcast and watch. You basically set the value in the controller you want to and create a broadcast event for it. In the controller that you would like to access the value, you put a watch and listen to any updates for the value.
The above way is also the dirtiest way to achieve what you want
A more elegant solution would involve create a model binding on the view and accessing those properties via logical progression on the controller you want to access that value in. You essentially create an angular service for your models and then access those services in the controllers.

Right way to tell all directives that data has already loaded

I have SPA and on the first page I load a big data object from the REST service.
The first page consists of the main part which resolved by controller, set of directives in the current scope which render some parts of received object and a header directive in the $rootscope which also render some part of received data.
I call API in the controller and when all data will be loaded I should notify about it all related directives for rendering loaded data.
Now I use $watch() and $watchGroup() for the same scope directives and $rootScope.$broadcast() for the header from the $rootscope.
Is there any more gracefully solution for it?
What is the best way to do this?
This sounds like a good use case for ngResource, which is an official Angular module for REST resources. I'd recommend you create a service for your resource like:
app.factory('Widget', function ($resource) {
return $resource('/api/v1/widgets/:id');
});
Then you can use it in your controller to handle the loading of your data.
app.controller('WidgetController', function ($scope, Widget) {
$scope.widgets = Widget.query({active: true});
});
In your views/templates/whatever, can bind right to widgets, which will be an array of widgets that match the query. The array will be empty while the widgets load, then it will be populated with the results -- and the binding will automatically update.
You can also bind to widgets.$resolved which (essentially) indicates whether the resource has finished loading or not.
Check out more about ngResource here.

Update variable in other controller

I have a page with a form in a modal. When the form in the modal is ready, I need to close the modal and display a message on the page. I would like the page and the modal to be separate controllers because they have different responsibilities. There are two methods I have found to notify the page that the form is ready:
Create a service which both controllers get injected and call methods on that
Make the modal controller a child of the page controller and let them share an object, like here: http://fdietz.github.io/recipes-with-angular-js/controllers/sharing-models-between-nested-controllers.html
The Angular documentation on scopes seem to say that controllers should not share variables but use services, but is that really the best way to go in this case?
Use services to share information about controllers, but instead of injecting the controllers to your service, inject the service to the controllers. Also, if you want to remain the binding between your view and your data, you need to use objects instead of primitive variables.
angular.module("MyApp", [])
.factory("Data", function() {
return { msg: "Shareable/Bindable data" }
})
.controller("One", function($scope, Data){
$scope.foo = Data;
})
.controller("Two", function($scope, Data){
$scope.bar = Data;
})
In this example, I could had just returned the data directly, instead of wrapping it in an object on my service. However, if we had done that (return "..." and $scope.foo = Data) , the variables {{foo}} or {{bar}} would only have a "shadow" copy of the factory information. Thus, we need to use {{foo.msg}} in our view and the message wrapping.
The full example is here in Codepen.io. Remove the { msg } and return the string instead to see what I mean.

Angularjs: two way data bindings and controller reload

If use routing and controllers, then model not save his states between controller reload. Angular create controller instance and new scope on every route load.
For example, i type something in input that have ng-model="something", go to another route, then back to first route. All my typed text is lost.
I need simple two way data binding between routes changing. As simple as possible, like ko.observable in knockoutjs. Or implicitly like in angular within one controller. Maybe with singleton $scope for controller?
I found the way, when i create service for saving data between route changing, and inject it into controller. In controller's constructor i create model with value from service, and $scope.watch this model for changes, and on change i set model's value to service.
Is there any simpler way?
You are right - services is right way for doing this. You can use it like so:
app.js
app.factory('paginationService', function() {
return {
cur: 1,
total: 9,
pageSize: 8
};
});
app.controller('Page1Ctrl', function($scope, paginationService) {
$scope.pagination = paginationService;
});
Page1.html
<div ng-controller="Page1Ctrl">
<h2>Page1</h2>
<p>curPage: <input type="number" ng-model="pagination.cur" /></p>
</div>
See full example.
You could inject $rootScope into your controller and use it to store globally accessible variables, though you would still have the same issue watching for changes. You could create a directive which would inject your service into the current scope, and have it bind watch handlers in the scope as well.

Resources