It's not a problem to achieve this!
The key thing to remember is to maintain the same object reference (arrays are objects in JavaScript) in your service.
Below is our straightforward HTML:
<div ng-controller = "companiesCtrl">
<ul ng-repeat="company in companies">
<li>{{company}}</li>
</ul>
</div>
This is how the service is implemented:
serviceDataCaching.service('companiesSrv', ['$timeout', function($timeout){
var self = this;
var httpResult = [
'company 1',
'company 2',
'company 3'
];
this.companies = ['preloaded company'];
this.getCompanies = function() {
// simulating an asynchronous operation
return $timeout(function(){
// maintaining the array object reference!!
self.companies.splice(0, self.companies.length);
// if you use the following code:
// self.companies = [];
// the controller will lose the reference to the array object as we are creating a new one
// consequently, it will not receive the changes made here!
for(var i=0; i< httpResult.length; i++){
self.companies.push(httpResult[i]);
}
return self.companies;
}, 3000);
}}]);
And here is the controller set up as requested:
serviceDataCaching.controller('companiesCtrl', function ($scope, companiesSrv) {
$scope.companies = companiesSrv.companies;
companiesSrv.getCompanies();
});
Explanation
As mentioned earlier, the key is to maintain the reference between the service and the controller. Once this is done correctly, you can bind your controller scope to a public property of your service without issues.
Here is a fiddle that sums it up.
In the code comments, you can try uncommenting the part that does not work, and you'll see how the controller loses the reference. Essentially, the controller will continue pointing to the old array while the service updates with a new one.
One more crucial point to remember: the $timeout triggers a $apply() on the rootScope, which is why the controller scope refreshes independently. Without this, using a regular setTimeout() would not update the company list in the controller.
To address this issue, you can:
- do nothing if your data is fetched with $http since it automatically calls $apply on success
- wrap your result in a $timeout(..., 0);
- inject $rootScope in the service and call $apply() on it after the asynchronous operation completes
- add $scope.$apply() in the controller on the getCompanies() promise success
Hope this explanation helps!