AngularJS Bind service array variable to controller scope

joshua.johnson.814 picture joshua.johnson.814 · Jan 7, 2014 · Viewed 16.4k times · Source

I have been able to properly bind an object with primitive data from a service to a scope variable from a controller but I'm having trouble doing the same thing with an array variable from the service.

service.js

myServices.factory('MyService', ['$http', function($http) {
var mySets = [];

  return {
  initMySets: function(userId, success, error) {
    $http.get(apiUrl + "/controller/getmysets", {params:{id:userId}}).success(function (data) {
      mySets = [];
      angular.copy(data, mySets);
    }).error(error);
  },

  getMySets: mySets


}]);

controllers.js

myControllers.controller('MenuController', ['$scope', 'UserService', 'MyService',
  function ($scope, UserService, MyService) {

  $scope.user = UserService.user;
  $scope.mySets = MyService.getMySets;

  $scope.logout = function() {
    UserService.logout();
  }
}]);

index.html

<nav id="app-menu"  ng-controller="MenuController" ng-class="{hide:!global.showMenu,slide:global.showMenu}">
  <div id="menu-head">
    <h4>{{user.Email}}</h4>
  </div>
  <ul>
    <div ng-switch on="user.UserId != null">
      <li ng-switch-when="true"><a href="#/main" ng-click="toggleMenu();logout();">Logout</a></li>
      <li ng-switch-when="false"><a href="#/login" ng-click="toggleMenu()">Login</a></li>
      <li ng-switch-when="true" ng-repeat="mySet in mySets">
        <a href="#/mySet /{{mySet.MySetId}}" ng-click="toggleMenu()">{{mySet.Label}}</a>
      </li>
    </div>
  </ul>
</nav>

I have a login function that calls initMySets on success passing in the userId and I know that the mySets variable in the service is getting populated properly on the angular copy but I'm not getting the actual update in the controller.

The $scope.user variable is being updated from the UserService, but the mySet ng-repeat isn't displaying the list from the service.

The data being returned from the http.get is an IEnumerable collection of complex objects from my MVC Web API controller. I'm not sure if that makes a difference.

Answer

Mickael picture Mickael · Jan 7, 2014

Binding does not work because your array (in your controller) never change.

When your initSets success function is called, your internal array points to a new array but your scope variable still points to your empty initial array.

Instead of create a new array, clear your initial array and push new items to initial array:

Replace that:

mySets = [];
angular.copy(data, mySets);

By that:

mySets.length = 0; // Clear initial array
mySets.push.apply(mySets, data); // Push data to initial array

See this fiddle (I simulate an asynchronous callback using $timeout) : http://jsfiddle.net/UJTPD