I'm fairly new to the ng-world so please go easy on my noobness :)
I've really tried to keep to the "angular" way of thinking in organizing my code and understanding it's dependency injection IoC methodologies.
One of my goals is dealing with REST services in SharePoint. The SharePoint integration is not the issue itself. I need to call a REST service on key-presses within UI elements to provide for suggestion lists. Like I said I've got the service wired up and working using ngResource. the service is a combination of the $resource element and a factory injected helper method that wires up the payload JSON required in the POST.
An example of how I can successfully test my service in a controller is:
peoplePickerControllers.controller('PeoplePickerSearchCtrl',
['$scope', 'PeoplePickerUtils',
function($scope, PeoplePickerUtils) {
$scope.Data = PeoplePickerUtils.resolveUser('scott');
}]);
This calls a method that was factory injected into my service module. When assigning the $scope element Data to the results then binding that data with:
{{ Data | json }}
I get the expected results.
However because this service method is something that needs to be called repeatedly during UI interaction and within almost every controller I wanted to bind it globally.
following a few different discussion threads I decided on using the app.run() to wire it up to the $rootScope like so:
myApp.run(['$rootScope','PeoplePickerUtils',
function($rootScope, PeoplePickerUtils) {
$rootScope.PeoplePicker = PeoplePickerUtils;
}
]);
I know this concept works, because the following code sample runs without problem:
myApp.run(['$rootScope','myUtilMethod',
function($rootScope, myUtilMethod) {
$rootScope.myGlobalFunc = function(params) { return params; };
}
]);
myApp.controller('MainCtrl', ['$scope', function($scope){}]);
</script>
<div ng-controller="MainCtrl">
<pre>{{ myGlobalFunc("foo") }}</pre>
</div>
Unfortunately when I bind the service reference in to the root scope and call it from within the page I get stuck in an eternal loop that eventually crashes Chrome. The errors are as follows:
http://errors.angularjs.org/1.3.15/$rootScope/infdig?p0=10&p1=%5B%5DREGEX_STRING_REGEXP @ angular.js:63$get.Scope.$digest @ angular.js:14346$get.Scope.$apply @ angular.js:14571done @ angular.js:9698completeRequest @ angular.js:9888requestLoaded @ angular.js:9829
angular.js:11655 Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
Watchers fired in the last 5 iterations: []
http://errors.angularjs.org/1.3.15/$rootScope/infdig?p0=10&p1=%5B%5D
at REGEX_STRING_REGEXP (angular.js:63)
at Scope.$get.Scope.$digest (angular.js:14346)
at Scope.$get.Scope.$apply (angular.js:14571)
at done (angular.js:9698)
at completeRequest (angular.js:9888)
at XMLHttpRequest.requestLoaded (angular.js:9829)(anonymous function) @ angular.js:11655$get @ angular.js:8596$get.Scope.$apply @ angular.js:14573done @ angular.js:9698completeRequest @ angular.js:9888requestLoaded @ angular.js:9829
angular.js:63 Uncaught Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
Watchers fired in the last 5 iterations: []
so I'm rather stuck, and believe it's because I don't fully understand how the promise of ngResoure works. My conclusions are:
When used inside of a controller to bind to $scope elements my service works as expected.
I've boiled all of this down to minimal code in a single page however unless you have a SharePoint 2013 or Office365 site the code won't exactly run. I'll share it if anyone thinks it is valuable to this discussion but I personally think it's my lack of understanding that's causing it.
When you invoke a function within interpolation {{xxx()}}
you need to be careful. Interpolation runs every digest cycle and you are calling a function within that, All is well, but then within the function you are making an service call or something which again triggers a digest cycle (ex:- after it has resolved/rejected and every promise chain with a resource call) or even if it returns a different object reference (with ng-bind
), interpolation expression gets evaluated again to stabilize the view. Angular will just go on hoping the view will be stable after every digest cycle, but apparently not. Angular does this loop till an max limit of 10 times (internally set but configurable though it will not solve your problem) internally and stops trying to stabilize displaying the error which you see in your console.
Just make the call when an event is triggered and not sure why exactly you want to do that. But you could as well do it in the controller right away when it is instantiated and bind the data as property to the view. Or bind the function myGlobalFunc('foo')
during a specific event happens.
So appropriate way would just be:
When used inside of a controller to bind to $scope elements my service works as expected.
Here is a simple enough example to replicate your issue:
angular.module('app', []).run(function($rootScope, $q) {
$rootScope.showData = function() {
var obj = {};
$q.when('hey').then(function(data) {
obj.name = data;
});
return obj;
}
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
{{showData().name}}
</div>