Angularjs: two way data bindings and controller reload - angularjs

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.

Related

Angular directive function from controller

I want to create a directive of a sidebar.
I have function in the controller that toggles the sidebar.
How can I access this function from any other controller in my application?
Thanks!
If you want to manipulate with your SideBar from whole your application, it is probably better way to save the state of SideBar in the Service. So you will have access to this service whenever you inject it, and you will able to change state of SideBar by changing this related Service value (It is possible because Services are always have only one instance, like Singleton pattern).
So, I will attach image which will show basic communication pattern for current case.
If we will change the state of active variable in the State Service, the SideBar Directive will be affected, because all three controllers are linked to the same instance of service.
Here Controllers service communication is small example of communication between controllers via service.
Hope it will help you!
I have function in the controller that toggles the sidebar
ItsĀ“not recomended to use any UI logic inside Controllers. In the World of Angular these things can be achieved by using declerative HTML.
<a ng-click="isReplyFormOpen = !isReplyFormOpen">Reply</a>
<div ng-show="isReplyFormOpen" id="replyForm"></div>
To answer your question: You can define a service which contains your function.
(function(){
angular.module('YourApp')
.factory('ToggleBar', function(){
function anyFunc(){
//Logic here...
}
return{
toggle: anyFunc
};
});
)();
Than inject the service to any Controller you whant to.
(function(){
angular.module('YourApp')
.controller('ControllerName',['ToggleBar',function(ToggleBar){
//Call the service func...
ToggleBar.toggle();
}]);
)();

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.

sharing data between two controllers which keeps on updating

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.

how do i bind a directive to an injected service instead of a parent or isolated scope?

related to this question: How do I create a dynamic nav which gets allowed menu items passed to it?
Basically, I have a nav outside of any views. The nav needs to display menu items which a user has access to.
I create the nav markup with a directive like so:
<tree family="treeFamily"></tree>
Where treeFamily is the data which will be used to build the navigation menu.
However, since my nav is outside of any views, it doesn't have a controller, so there is no scope variable called treeFamily. Which means the directive doesn't get any data to create a navigation.
I originally thought I could just inject a service with the data for the menu items, but then there is no way that I can see to tell an angular directive to use data taken from an injected service for binding.
The only other way that seems to be possible is to have a $rootScope variable called treeFamily and have the directive generated markup bind to that instead.
I still think you want to have a look at angular-ui router, as mentioned I in your previous question
https://github.com/angular-ui/ui-router
However, the way I'd do this without angular-ui-router is to create the service, then just inject the service in to the directive when you declare that, and use the data in there as per http://docs.angularjs.org/guide/directive.
For example:
angular.module('yourModule').service('yourService', function() {
// define your service
});
angular.module('yourModule').directive('yourDirective', function(yourService) {
return {
link: function postLink(scope, element, attrs) {
// you can now define your directive and access your yourService service
}
};
});
If you don't want to use a $rootScope variable here is a slightly hacky solution but you could get the scope by the element.
Example.
Say your data is applied to a test controller so you have a element like this
<div id="test" ng-controller="test">
You could do this example using jQuery (not required)
$('#test').scope().treeFamily
There it is you have access to the scope that you need to get your data from, demo in progress.
Demo: http://jsfiddle.net/hq26h/
In the demo the random directive is accessing the treeFamily data from the test controller when the directive is outside the controller.
If you wan't your service data to be bindable, you can do this
app.directive('something', function( $someNavDataService ) {
return function( $scope ) {
$scope.navData = $someNavDataService;
};
});

Resources