Models directly $ looked and call View using Angular - a good idea?
I ran into a problem (which I think I understand), but I don't understand what the solution is.
In a nutshell, I have BackendService
one that wraps some non-Angular object model (in my case SharePoint, but that's not the point). I created this BackendService
one so it can return Angular-Component Entities ( items
) so that I can do something like the following:
angular.module("app", [])
.factory("BackendService", function(){
return new BackendService();
})
.controller("MainCtrl", function($scope, BackendService){
BackendService.GetItems()
.then(function(items){
$scope.Items = items;
$scope.$apply();
});
});
So far so good.
Also, I wanted each to item
be self-contained and the ViewModel-y in a way that could be used directly in the View. In other words, I wanted to do the following (notice the ng-show
and button ng-click
):
<div ng-controller="MainCtrl">
<div ng-repeat="item in Items">
<input ng-model="item.fieldA" type="text"/>
<input ng-model="item.fieldB" type="text"/>
<button ng-show="item.IsDirty()" ng-click="item.Save()">Save</button>
</div>
</div>
The button is displayed immediately when there is any change (which sets the dirty flag), but when item.Save()
- the async function - is called where the dirty flag is disabled, that change is not visible in the DOM.
So the problem is : the button is not hiding when item.IsDirty() === false
.
My understanding is that there item.Save()
is an async function that uses an object model that uses Ajax under the covers (which doesn't use $ http since it doesn't know about Angular), thus bypassing the digest loop. Because of this, a change in c is item.IsDirty()
never reflected in the DOM.
Questions:
- How do I understand the question correctly?
- Have I insulted Angular best practice with this approach?
- Should I do something now? how to
<button ng-click="SaveItem(item)">
call$scope.$apply
inside it?
Edit (in response to Gordon's answer):
- Is it a good idea to pass the $ scope or use the $ rootScope deep into the services, or if the service is going to be Angular-significant? If not, which would be preferable?
Thank!
The problem is that your scope.items array is not tied to any of your service data. I would solve this problem by having an object property on the ain object in your service that is bound to the object property.
BackendService.loadData()
.then(function() {
$scope.data = BackendService.data;
});
// data is an object with a property items
Then, as soon as there are changes to your service data, update the array of local elements and they will be tracked using angular data binding.
And I finally understood. I was able to get it around it using emit to run the app: http://plnkr.co/edit/F8rLK2?p=preview
See this Q&A for deets: angularjs ng-show with expression promise