I\'m trying to figure out how you handle binding properly when my data is stored in a service.
I can get things working if it put the service into the $scope and the
I think, even more elegant is to work with promises (see $q.deferred()
) and to resolve them asynchronously. In the promise function you can then assign the data to $scope
's members.
There are two ways to do bind the data from a service: 1) By value (will require a watcher as done above to check for variable changes to the service primitive value) 2) By reference (values are directly linked) which is my preferred method of data binding.
I will only explain the second possibility since the accepted answer already shows how a watcher can be implemented. This blog describes what I am going to explain very well.
I created this plunk to illustrate data binding by reference.
Here is the code from the plunk:
HTML
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<script data-require="angularjs@1.5.0" data-semver="1.5.0" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-controller="myAppCntrl">
<h1>Hello Plunker!</h1>
<h3>By value</h3>
<p>{{byValue}}</p>
<p>{{objByValue}}</p>
<h3>By object in service reference</h3>
<p>{{byRefence.stringPrimitive}}</p>
<h3>By reference to service singleton</h3>
<p>{{myservice.stringPrimitive}}</p>
<p style="color: green">of course, you can reference an object through the service as well</p>
<p>{{myservice.objectWithPrimitive.stringPrimitive}}</p>
<button ng-click=update()>Update strings on service</button>
<br />
<button ng-click=setDefaults()>Restore Defaults</button>
</body>
</html>
JAVASCRIPT
var myApp = angular.module("myApp", []);
myApp.controller('myAppCntrl', function($scope, myAppService){
$scope.myservice = myAppService;
$scope.byValue = myAppService.stringPrimitive;
$scope.objByValue = myAppService.objectWithPrimitive.stringPrimitive;
$scope.byRefence = myAppService.objectWithPrimitive;
$scope.update = function () {
myAppService.stringPrimitive = "updated string";
myAppService.objectWithPrimitive.stringPrimitive = "updated string here too";
};
$scope.setDefaults = function () {
myAppService.stringPrimitive = 'string primitive';
myAppService.objectWithPrimitive.stringPrimitive = 'string primitive';
};
});
myApp.service('myAppService', function(){
this.stringPrimitive = 'string primitive';
this.objectWithPrimitive = {
stringPrimitive: 'string primitive'
};
});
So how does this work?
It is important to understand that this has little to do with how angular works, and a lot to do with how Javascript works. When a variable is set equal to a primitive value (or passed to a function) in javascript (integer, string, etc.) the var is set by value. This means that the the new variable is a copy of the variable you are setting it equal to with a new location in memory. When a variable is set equal to an object (or passed to a function) in javascript the var is set by reference.
What does this mean?
When a $scope var is set by value, and the service variable changes, since the $scope variable is only a copy of the service variable, the service variable no longer has anything to do with the service variable and will not change when the service var does.
When the $scope var is set equal to and object, it is assigned by Reference. This means that when the service object (note that the service is an object since it is instantiated with the new keyword and you can refer to that object with "this" inside the service) or any objects on the service that are referenced are changed, any $scope variable that reference those objects will update as well.
You can bind to services using $watch
and passing a function:
$scope.$watch( function () { return myService.drawing; }, function ( drawing ) {
// handle it here. e.g.:
$scope.drawing = drawing;
});
And then use $scope.drawing
in your templates and they will automatically update:
<div ng-controller="MyOtherCtl">
{{ drawing }}
</div>