Binding variables from Service/Factory to Controllers - angularjs

I have a variable that will be used by one or more Controllers, changed by Services.
In that case, I've built a service that keeps this variable in memory, and share between the controllers.
The problem is: Every time that the variable changes, the variables in the controllers aren't updated in real time.
I create this Fiddle to help. http://jsfiddle.net/ncyVK/
--- Note that the {{countService}} or {{countFactory}} is never updated when I increment the value of count.
How can I bind the Service/Factory variable to $scope.variable in the Controller? What I'm doing wrong?

You can't bind variables. But you can bind variable accessors or objects which contain this variable. Here is fixed jsfiddle.
Basically you have to pass to the scope something, which can return/or holds current value. E.g.
Factory:
app.factory('testFactory', function(){
var countF = 1;
return {
getCount : function () {
return countF; //we need some way to access actual variable value
},
incrementCount:function(){
countF++;
return countF;
}
}
});
Controller:
function FactoryCtrl($scope, testService, testFactory)
{
$scope.countFactory = testFactory.getCount; //passing getter to the view
$scope.clickF = function () {
$scope.countF = testFactory.incrementCount();
};
}
View:
<div ng-controller="FactoryCtrl">
<!-- this is now updated, note how count factory is called -->
<p> This is my countFactory variable : {{countFactory()}}</p>
<p> This is my updated after click variable : {{countF}}</p>
<button ng-click="clickF()" >Factory ++ </button>
</div>

It's not good idea to bind any data from service,but if you need it anymore,I suggest you those following 2 ways.
1) Get that data not inside your service.Get Data inside you controller and you will not have any problem to bind it.
2) You can use AngularJs Events feature.You can even send data to through that event.
If you need more with examples here is the article which maybe can help you.
http://www.w3docs.com/snippets/angularjs/bind-value-between-service-and-controller-directive.html

Related

How to access a dropdown in another controller scope in angularjs

I have a controller name is ParentController, which has a dropdown named ddlState. How to access this dropdown in another controller named CityController in Angular JS
use a factory.
Here is a sample for simple data exchange
app.factory('dataExchange', function() {
var ret = {
getData: getData,
setData: setData
};
var data = {};
return ret;
function getData() {
return data;
}
function setData(x) {
data = x;
}
});
Simply give your object to setData in your parent controller, and get it back in your child with getData
You have different ways to work with this,
1. It is always better to have the drop downs through a directive.then you can use the same directive for multiple drop down in multiple controllers by using $on function.
2. Else if you want to write and repeat the drop down code in all html and controllers, you can go with local storage system, So once call the API result and store in local storage (browser level), in other controllers also with out calling the API you can append the data into drop down from local storage.
Other way is keep the drop down values in a $rootScope variable,and you can use in where ever you want. (but this way is not recommended)

Creating <td> directive with Angular 1.5

I am trying to make an Angular 1.5 directive work within an ng-repeat for a table. A few things I need this to do (and please, if I am going at this the completely wrong way, let me know):
1) Update the html whenever new results are provided. Most importantly, the link function gets called once, with an empty result, and never called again. So, my table is blank. Always.
2) Inside the 'template' of the directive, I reference the controller's name and a method which is type coupling. Is the 'right' way to do this?
Here's my code snippets...
module-a.view.html:
<table>
<tr ng-repeat="(ii,result) in moduleACtrl.results">
<td>This is a normal TD</td>
<td-result result="{{result}}" ctrlName="moduleACtrl"></td-result>
</tr>
</table>
UPDATED
common.td-result.directive.js
(function(){
'use strict';
/* global angular */// ESLINT
angular.module('common').directive('tdResult',Directive);
Directive.$inject = ['$compile'];
function Directive($compile){
return {
restrict : 'E',
scope : {
result : '#',
ctrlName : '#'
},
template: '<td>{{result.prop1}}</td>\
<td>{{result.prop2}}</td>\
<td>{{result.prop3}}</td>\
<td><div ng-click="ctrlName.doSomething()">Something Goes Here {{ctrlName}}</div></td>'
};
}
})();
After reading a number of related questions on StackOverflow, and re-reviewing Angular's Directives documentation, I cannot figure out how to do what I want.
The overall context that got me here is that I have an OpenLayers 3 map, displaying result data from a query. I have the result data on the map interactively displaying result data when you click on it, like this: http://openlayers.org/en/latest/examples/getfeatureinfo-image.html
The difference though, is that I am using Angular 1.5. I have a ModuleA with a controller and view that house the map. I have another ModuleCommon that houses a service that handles creation of the map object and hands it to ModuleA.controller (or any controller who wants the map service). So, now, I have to create an interface for the map service that can generically handle displaying data to any client who wants to render said data.
I decided this was all a bad idea and that I need to step way back. First, the map object should not be responsible for displaying the data. The map is responsible for handling the 'singleclick' event and getting me a feature.
So, I decided that the controller, which instantiates the map object via the map service, will simply be responsible for creating and sending a callback to the map object so the map object knows what it's client wants on a singleclick. The getFeature is the map object's responsibility, and what to do with the feature's id is the client's (i.e. controller's) responsibility.
Whew!
Map code:
map.on('singleclick',function(event){
map.forEachFeatureAtPixel(event.pixel,function(feature){
callback(feature.getId());
});
});
Controller Code:
...
function mapCallback(someId){
var elem = angular.element('#info');
if ( someId === undefined ) {
elem.slideUp(); // Hide element
} else {
for (var data, ii = 0, len = vm.dataList.length; ii < len; ii++) {
data = vm.dataList[ii];
if ( someId === data.property ) {
vm.currentData = data;
$scope.$apply();
elem.slideDown(); // Show element
break;
} else {
elem.slideUp(); // Hide element
}
}
}
}
...
1) The Map is de-coupled from the data pertaining to the feature.
2) The Controller controls what happens when the map selects its data.
3) The HTML stays in the Controller's associated Component's templateUrl where it belongs!

How to display the value of other controllers in one view dynamically

I am working on an application were index page and inside that I am showing multiple views, In index nav bar I have to show notification count and User name which comes from 2 different controllers,
I am able to display the notification count and User name successfully, but the issue is the values are not changing dynamically.
We need to refresh the page for the new values.
What can I do in this situation can any one please guide me.
I'm guessing you're watching the value directly and not by some object wrapper. In this case javascript isn't actually updating the variable, but assigning a complete new one. Anything out of the function scope that updates the variable will never receive the new value.
The solution is simple; wrap the value in an object and share/inject that object.
angular.module('myApp')
.value('myPageState', {
notificationCount: 0
});
angular.module('myApp')
.controller('myController', function($scope, myPageState) {
$scope.myPageState = myPageState;
});
<div class="my-notification-thingy"> {{ myPageState.notificationCount }} </div>
You can achieve it by:
Maintain those values in rootScope so that you
will have the two way binding.
Making use of emit to notify the parent controller about value changes. This will work only if those two controllers are present in child elements.
In child controllers fire event on value update:
$scope.$emit('valueChanged', {value: val});
In parent controller receive event value:
$scope.$on('valueChanged', function(event, args) {
console.log(args.value);
});

How to watch a parent controller variable changed by a child

I'm trying to save user.preferences everytime they change, so, user.preferences is an App variable.
HTML
...
ng-controller="AppController as App"
...
On app.js
vm.preferences = localStorage.preferences === undefined ? initialPreferences : JSON.parse(localStorage.preferences) ;
$scope.$watch('App.preferences',function() {
localStorage.preferences = JSON.stringify(vm.preferences);
});
The child controller CAN change the variable but the watcher doesn't trigger. Any clue? Thanks in advance
Googled a little more, if you wan't to watch an entire Object you must specify the third argument of $watch: objectEquality.
From AngularJS Docs:
Compare for object equality using angular.equals instead of comparing for reference equality.
Watching an entire object:
$scope.$watch('App.preferences',function() {
localStorage.preferences = JSON.stringify(vm.preferences);
},true);

AngularJS : The correct way of binding to a service properties

I’m looking for the best practice of how to bind to a service property in AngularJS.
I have worked through multiple examples to understand how to bind to properties in a service that is created using AngularJS.
Below I have two examples of how to bind to properties in a service; they both work. The first example uses basic bindings and the second example used $scope.$watch to bind to the service properties
Are either of these example preferred when binding to properties in a service or is there another option that I’m not aware of that would be recommended?
The premise of these examples is that the service should updated its properties “lastUpdated” and “calls” every 5 seconds. Once the service properties are updated the view should reflect these changes. Both these example work successfully; I wonder if there is a better way of doing it.
Basic Binding
The following code can be view and ran here: http://plnkr.co/edit/d3c16z
<html>
<body ng-app="ServiceNotification" >
<div ng-controller="TimerCtrl1" style="border-style:dotted">
TimerCtrl1 <br/>
Last Updated: {{timerData.lastUpdated}}<br/>
Last Updated: {{timerData.calls}}<br/>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.5/angular.js"></script>
<script type="text/javascript">
var app = angular.module("ServiceNotification", []);
function TimerCtrl1($scope, Timer) {
$scope.timerData = Timer.data;
};
app.factory("Timer", function ($timeout) {
var data = { lastUpdated: new Date(), calls: 0 };
var updateTimer = function () {
data.lastUpdated = new Date();
data.calls += 1;
console.log("updateTimer: " + data.lastUpdated);
$timeout(updateTimer, 5000);
};
updateTimer();
return {
data: data
};
});
</script>
</body>
</html>
The other way I solved binding to service properties is to use $scope.$watch in the controller.
$scope.$watch
The following code can be view and ran here: http://plnkr.co/edit/dSBlC9
<html>
<body ng-app="ServiceNotification">
<div style="border-style:dotted" ng-controller="TimerCtrl1">
TimerCtrl1<br/>
Last Updated: {{lastUpdated}}<br/>
Last Updated: {{calls}}<br/>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.5/angular.js"></script>
<script type="text/javascript">
var app = angular.module("ServiceNotification", []);
function TimerCtrl1($scope, Timer) {
$scope.$watch(function () { return Timer.data.lastUpdated; },
function (value) {
console.log("In $watch - lastUpdated:" + value);
$scope.lastUpdated = value;
}
);
$scope.$watch(function () { return Timer.data.calls; },
function (value) {
console.log("In $watch - calls:" + value);
$scope.calls = value;
}
);
};
app.factory("Timer", function ($timeout) {
var data = { lastUpdated: new Date(), calls: 0 };
var updateTimer = function () {
data.lastUpdated = new Date();
data.calls += 1;
console.log("updateTimer: " + data.lastUpdated);
$timeout(updateTimer, 5000);
};
updateTimer();
return {
data: data
};
});
</script>
</body>
</html>
I’m aware that I can use $rootscope.$broadcast in the service and $root.$on in the controller, but in other examples that I’ve created that use $broadcast/$on the first broadcast is not captured by the controller, but additional calls that are broadcasted are triggered in the controller. If you are aware of a way to solve $rootscope.$broadcast problem, please provide an answer.
But to restate what I mentioned earlier, I would like to know the best practice of how to bind to a service properties.
Update
This question was originally asked and answered in April 2013. In May 2014, Gil Birman provided a new answer, which I changed as the correct answer. Since Gil Birman answer has very few up-votes, my concern is that people reading this question will disregard his answer in favor of other answers with many more votes. Before you make a decision on what's the best answer, I highly recommend Gil Birman's answer.
Consider some pros and cons of the second approach:
0 {{lastUpdated}} instead of {{timerData.lastUpdated}}, which could just as easily be {{timer.lastUpdated}}, which I might argue is more readable (but let's not argue... I'm giving this point a neutral rating so you decide for yourself)
+1 It may be convenient that the controller acts as a sort of API for the markup such that if somehow the structure of the data model changes you can (in theory) update the controller's API mappings without touching the html partial.
-1 However, theory isn't always practice and I usually find myself having to modify markup and controller logic when changes are called for, anyway. So the extra effort of writing the API negates it's advantage.
-1 Furthermore, this approach isn't very DRY.
-1 If you want to bind the data to ng-model your code become even less DRY as you have to re-package the $scope.scalar_values in the controller to make a new REST call.
-0.1 There's a tiny performance hit creating extra watcher(s). Also, if data properties are attached to the model that don't need to be watched in a particular controller they will create additional overhead for the deep watchers.
-1 What if multiple controllers need the same data models? That means that you have multiple API's to update with every model change.
$scope.timerData = Timer.data; is starting to sound mighty tempting right about now... Let's dive a little deeper into that last point... What kind of model changes were we talking about? A model on the back-end (server)? Or a model which is created and lives only in the front-end? In either case, what is essentially the data mapping API belongs in the front-end service layer, (an angular factory or service). (Note that your first example--my preference-- doesn't have such an API in the service layer, which is fine because it's simple enough it doesn't need it.)
In conclusion, everything does not have to be decoupled. And as far as decoupling the markup entirely from the data model, the drawbacks outweigh the advantages.
Controllers, in general shouldn't be littered with $scope = injectable.data.scalar's. Rather, they should be sprinkled with $scope = injectable.data's, promise.then(..)'s, and $scope.complexClickAction = function() {..}'s
As an alternative approach to achieve data-decoupling and thus view-encapsulation, the only place that it really makes sense to decouple the view from the model is with a directive. But even there, don't $watch scalar values in the controller or link functions. That won't save time or make the code any more maintainable nor readable. It won't even make testing easier since robust tests in angular usually test the resulting DOM anyway. Rather, in a directive demand your data API in object form, and favor using just the $watchers created by ng-bind.
Example
http://plnkr.co/edit/MVeU1GKRTN4bqA3h9Yio
<body ng-app="ServiceNotification">
<div style="border-style:dotted" ng-controller="TimerCtrl1">
TimerCtrl1<br/>
Bad:<br/>
Last Updated: {{lastUpdated}}<br/>
Last Updated: {{calls}}<br/>
Good:<br/>
Last Updated: {{data.lastUpdated}}<br/>
Last Updated: {{data.calls}}<br/>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.5/angular.js"></script>
<script type="text/javascript">
var app = angular.module("ServiceNotification", []);
function TimerCtrl1($scope, Timer) {
$scope.data = Timer.data;
$scope.lastUpdated = Timer.data.lastUpdated;
$scope.calls = Timer.data.calls;
};
app.factory("Timer", function ($timeout) {
var data = { lastUpdated: new Date(), calls: 0 };
var updateTimer = function () {
data.lastUpdated = new Date();
data.calls += 1;
console.log("updateTimer: " + data.lastUpdated);
$timeout(updateTimer, 500);
};
updateTimer();
return {
data: data
};
});
</script>
</body>
UPDATE: I've finally come back to this question to add that I don't think that either approach is "wrong". Originally I had written that Josh David Miller's answer was incorrect, but in retrospect his points are completely valid, especially his point about separation of concerns.
Separation of concerns aside (but tangentially related), there's another reason for defensive copying that I failed to consider. This question mostly deals with reading data directly from a service. But what if a developer on your team decides that the controller needs to transform the data in some trivial way before the view displays it? (Whether controllers should transform data at all is another discussion.) If she doesn't make a copy of the object first she might unwittingly cause regressions in another view component which consumes the same data.
What this question really highlights are architectural shortcomings of the typical angular application (and really any JavaScript application): tight coupling of concerns, and object mutability. I have recently become enamored with architecting application with React and immutable data structures. Doing so solves the following two problems wonderfully:
Separation of concerns: A component consumes all of it's data via props and has little-to-no reliance on global singletons (such as Angular services), and knows nothing about what happened above it in the view hierarchy.
Mutability: All props are immutable which eliminates the risk of unwitting data mutation.
Angular 2.0 is now on track to borrow heavily from React to achieve the two points above.
From my perspective, $watch would be the best practice way.
You can actually simplify your example a bit:
function TimerCtrl1($scope, Timer) {
$scope.$watch( function () { return Timer.data; }, function (data) {
$scope.lastUpdated = data.lastUpdated;
$scope.calls = data.calls;
}, true);
}
That's all you need.
Since the properties are updated simultaneously, you only need one watch. Also, since they come from a single, rather small object, I changed it to just watch the Timer.data property. The last parameter passed to $watch tells it to check for deep equality rather than just ensuring that the reference is the same.
To provide a little context, the reason I would prefer this method to placing the service value directly on the scope is to ensure proper separation of concerns. Your view shouldn't need to know anything about your services in order to operate. The job of the controller is to glue everything together; its job is to get the data from your services and process them in whatever way necessary and then to provide your view with whatever specifics it needs. But I don't think its job is to just pass the service right along to the view. Otherwise, what's the controller even doing there? The AngularJS developers followed the same reasoning when they chose not to include any "logic" in the templates (e.g. if statements).
To be fair, there are probably multiple perspectives here and I look forward to other answers.
Late to the party, but for future Googlers - don't use the provided answer.
JavaScript has a mechanism of passing objects by reference, while it only passes a shallow copy for values "numbers, strings etc".
In above example, instead of binding attributes of a service, why don't we expose the service to the scope?
$scope.hello = HelloService;
This simple approach will make angular able to do two-way binding and all the magical things you need. Don't hack your controller with watchers or unneeded markup.
And if you are worried about your view accidentally overwriting your service attributes, use defineProperty to make it readable, enumerable, configurable, or define getters and setters. You can gain lots of control by making your service more solid.
Final tip: if you spend your time working on your controller more than your services then you are doing it wrong :(.
In that particular demo code you supplied I would recommend you do:
function TimerCtrl1($scope, Timer) {
$scope.timer = Timer;
}
///Inside view
{{ timer.time_updated }}
{{ timer.other_property }}
etc...
Edit:
As I mentioned above, you can control the behaviour of your service attributes using defineProperty
Example:
// Lets expose a property named "propertyWithSetter" on our service
// and hook a setter function that automatically saves new value to db !
Object.defineProperty(self, 'propertyWithSetter', {
get: function() { return self.data.variable; },
set: function(newValue) {
self.data.variable = newValue;
// let's update the database too to reflect changes in data-model !
self.updateDatabaseWithNewData(data);
},
enumerable: true,
configurable: true
});
Now in our controller if we do
$scope.hello = HelloService;
$scope.hello.propertyWithSetter = 'NEW VALUE';
our service will change the value of propertyWithSetter and also post the new value to database somehow!
Or we can take any approach we want.
Refer to the MDN documentation for defineProperty.
I think this question has a contextual component.
If you're simply pulling data from a service & radiating that information to it's view, I think binding directly to the service property is just fine. I don't want to write a lot of boilerplate code to simply map service properties to model properties to consume in my view.
Further, performance in angular is based on two things. The first is how many bindings are on a page. The second is how expensive getter functions are. Misko talks about this here
If you need to perform instance specific logic on the service data (as opposed to data massaging applied within the service itself), and the outcome of this impacts the data model exposed to the view, then I would say a $watcher is appropriate, as long as the function isn't terribly expensive. In the case of an expensive function, I would suggest caching the results in a local (to controller) variable, performing your complex operations outside of the $watcher function, and then binding your scope to the result of that.
As a caveat, you shouldn't be hanging any properties directly off your $scope. The $scope variable is NOT your model. It has references to your model.
In my mind, "best practice" for simply radiating information from service down to view:
function TimerCtrl1($scope, Timer) {
$scope.model = {timerData: Timer.data};
};
And then your view would contain {{model.timerData.lastupdated}}.
Building on the examples above I thought I'd throw in a way of transparently binding a controller variable to a service variable.
In the example below changes to the Controller $scope.count variable will automatically be reflected in the Service count variable.
In production we're actually using the this binding to update an id on a service which then asynchronously fetches data and updates its service vars. Further binding that means that controllers automagically get updated when the service updates itself.
The code below can be seen working at http://jsfiddle.net/xuUHS/163/
View:
<div ng-controller="ServiceCtrl">
<p> This is my countService variable : {{count}}</p>
<input type="number" ng-model="count">
<p> This is my updated after click variable : {{countS}}</p>
<button ng-click="clickC()" >Controller ++ </button>
<button ng-click="chkC()" >Check Controller Count</button>
</br>
<button ng-click="clickS()" >Service ++ </button>
<button ng-click="chkS()" >Check Service Count</button>
</div>
Service/Controller:
var app = angular.module('myApp', []);
app.service('testService', function(){
var count = 10;
function incrementCount() {
count++;
return count;
};
function getCount() { return count; }
return {
get count() { return count },
set count(val) {
count = val;
},
getCount: getCount,
incrementCount: incrementCount
}
});
function ServiceCtrl($scope, testService)
{
Object.defineProperty($scope, 'count', {
get: function() { return testService.count; },
set: function(val) { testService.count = val; },
});
$scope.clickC = function () {
$scope.count++;
};
$scope.chkC = function () {
alert($scope.count);
};
$scope.clickS = function () {
++testService.count;
};
$scope.chkS = function () {
alert(testService.count);
};
}
I think it's a better way to bind on the service itself instead of the attributes on it.
Here's why:
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.7/angular.min.js"></script>
<body ng-app="BindToService">
<div ng-controller="BindToServiceCtrl as ctrl">
ArrService.arrOne: <span ng-repeat="v in ArrService.arrOne">{{v}}</span>
<br />
ArrService.arrTwo: <span ng-repeat="v in ArrService.arrTwo">{{v}}</span>
<br />
<br />
<!-- This is empty since $scope.arrOne never changes -->
arrOne: <span ng-repeat="v in arrOne">{{v}}</span>
<br />
<!-- This is not empty since $scope.arrTwo === ArrService.arrTwo -->
<!-- Both of them point the memory space modified by the `push` function below -->
arrTwo: <span ng-repeat="v in arrTwo">{{v}}</span>
</div>
<script type="text/javascript">
var app = angular.module("BindToService", []);
app.controller("BindToServiceCtrl", function ($scope, ArrService) {
$scope.ArrService = ArrService;
$scope.arrOne = ArrService.arrOne;
$scope.arrTwo = ArrService.arrTwo;
});
app.service("ArrService", function ($interval) {
var that = this,
i = 0;
this.arrOne = [];
that.arrTwo = [];
$interval(function () {
// This will change arrOne (the pointer).
// However, $scope.arrOne is still same as the original arrOne.
that.arrOne = that.arrOne.concat([i]);
// This line changes the memory block pointed by arrTwo.
// And arrTwo (the pointer) itself never changes.
that.arrTwo.push(i);
i += 1;
}, 1000);
});
</script>
</body>
You can play it on this plunker.
I would rather keep my watchers a less as possible. My reason is based on my experiences and one might argue it theoretically.
The issue with using watchers is that you can use any property on scope to call any of the methods in any component or service you like.
In a real world project, pretty soon you'll end up with a non-tracable (better said hard to trace) chain of methods being called and values being changed which specially makes the on-boarding process tragic.
To bind any data,which sends service is not a good idea (architecture),but if you need it anymore I suggest you 2 ways to do that
1) you can get the data not inside you service.You can get data inside your controller/directive and you will not have a problem to bind it anywhere
2) you can use angularjs events.Whenever you want,you can send a signal(from $rootScope) and catch it wherever you want.You can even send a data on that eventName.
Maybe this can help you.
If you need more with examples,here is the link
http://www.w3docs.com/snippets/angularjs/bind-value-between-service-and-controller-directive.html
What about
scope = _.extend(scope, ParentScope);
Where ParentScope is an injected service?
The Most Elegant Solutions...
app.service('svc', function(){ this.attr = []; return this; });
app.controller('ctrl', function($scope, svc){
$scope.attr = svc.attr || [];
$scope.$watch('attr', function(neo, old){ /* if necessary */ });
});
app.run(function($rootScope, svc){
$rootScope.svc = svc;
$rootScope.$watch('svc', function(neo, old){ /* change the world */ });
});
Also, I write EDAs (Event-Driven Architectures) so I tend to do something like the following [oversimplified version]:
var Service = function Service($rootScope) {
var $scope = $rootScope.$new(this);
$scope.that = [];
$scope.$watch('that', thatObserver, true);
function thatObserver(what) {
$scope.$broadcast('that:changed', what);
}
};
Then, I put a listener in my controller on the desired channel and just keep my local scope up to date this way.
In conclusion, there's not much of a "Best Practice" -- rather, its mostly preference -- as long as you're keeping things SOLID and employing weak coupling. The reason I would advocate the latter code is because EDAs have the lowest coupling feasible by nature. And if you aren't too concerned about this fact, let us avoid working on the same project together.
Hope this helps...

Resources