Patrick Olden
Patrick Olden

Reputation: 11

ng-options not updating when model changed

I have a JSON object that looks like:

[
   {
    "empName": "John",
    "ID": 1
   },
   {
    "empName": "Sam",
    "ID": 2
   },
   {
    "empName": "Ben",
    "ID": 3
   }
]

In the view I want a dropdown where the user selects one of the names. I'm using ng-options to achieve this:

<select ng-options="item as item.empName for item in employees track by item.ID" ng-model="emp.selected">
</select>  

If I hard-code the JSON into the variable employees in my controller the select renders. However if I use:

$.getJSON("path to JSON file",function(json){
    $scope.employees = json;
});

The select is not populated. I've tried adding in $scope.$apply() to no avail. Any suggestions?

Update 1

Taking on board the answer from Iso I'm still left with the select not binding. For example If my javascript is:

app.controller('Ctrl', ['$scope', '$http', function($scope, $http) {

    $scope.employees = [
       {
        "empName": "John",
        "ID": 1
       },
    ];

    $http.get(" --PATH TO JSON-- ").then(function (res) {
        $scope.employees = res.data;
        console.log($scope.employees);
    });
}]);

The select is still only populated with the first name 'John' despite the fact that the console.log returns the full object with all three names.

Upvotes: 0

Views: 47

Answers (3)

Iso
Iso

Reputation: 3238

You need to either call $scope.$evalAsync(), or use $http instead of jQuery here (which I would recommend):

$http.get("path to JSON file").then(function (res) {
  $scope.employees = res.data;
});

The reason for this is that $http is aware of AngularJS' digest cycle, whereas jQuery is not.

Refrain from using $scope.$apply() (which can fail if a digest cycle is in progress), and $timeout (which is heavy since it provokes a digest cycle of all your scopes).

Upvotes: 1

itamar
itamar

Reputation: 3967

You should use promises with the $q library in Angular.

var getEmployees = function () {
        var deferred = $q.defer();
        $.getJSON("path to JSON file", function (json) {
            deferred.resolve(json);
        });
        return deferred.promise;
    }

    getEmployees().then(res){
        $scope.employees = res.data;
    }

EDIT If you use $timeout is not really as correct a solution, as it doesn't give you control over the synchronicity. However, using $http to make your calls comes with promises built in, I believe.

Upvotes: 0

Shashank Agrawal
Shashank Agrawal

Reputation: 25797

Wrap your code inside $timeout:

$.getJSON("path to JSON file", function (json) {
    $timeout(function () {
        $scope.employees = json;
    })
});

The call to $apply may fail when the digest cycle is already in progress.

But consider using the $http instead of using jQuery to pull data.

Upvotes: 0

Related Questions