Question

I am trying to create a dropdown menu with AngularJS. I created a factory (‘disResource’) and use $resource to retrieve data from a database.

Factory:

angular.module('app').factory('disResource', ['$resource', function($resource) {
  return $resource('/api/disciplines/:dis_id', {}, {
    query: {method:'GET', params: {}, isArray:true},
    create: { method: 'POST' },
    show: { method: 'GET' },
    update: { method: 'PUT', params: {dis_id: '@dis_id'}},
    delete: { method: 'DELETE', params: {dis_id: '@dis_id'} }
  });
}]);

Controller:

angular.module("app").controller("AdminDisSearchCtrl", ['$scope', 'disResource', function ($scope, disResource) { 

  disResource.query(function(reply) {
    $scope.results = { disciplines: reply};
  });
}]);

View:

<h2>Select Discipline:</h2>
  <select data-ng-model="filterItem.discipline" data-ng-options="item.dis_name for item in results.disciplines"></select>  

Everything works well, the dropdown is populated with the $resource data and Console.log indicates that everything gets loaded.

console.log($scope):

...
results: Object
disciplines: Array[6]
0: Resource
  $$hashKey: "00F"
  created_at: "2014-03-13 18:59:25"
  dis_id: 1
  dis_name: "AAA"
  updated_at: "2014-03-13 18:59:25"
  __proto__: Resource
1: Resource
...

However, the dropdown shows a blank space. When I try to specify the default dropdown item in the controller

$scope.filterItem = {
  discipline: $scope.results.disciplines[0]    
};

I receive a Console Error: TypeError: Cannot read property 'disciplines' of undefined

When I hardcode the data into the controller, everything works:

$scope.results = {
  disciplines: [
   { dis_id:1, dis_name:'AAA' },
   { dis_id:2, dis_name:'BBB' }
  ]
};

$scope.filterItem = {
  discipline: $scope.results.disciplines[0]
};

console.log($scope):

...
results: Object
  disciplines: Array[2]
  0: Object
    $$hashKey: "007"
    dis_id: 1 
    dis_name: "AAA"
    __proto__: Object
  1: Object
  ...

Question: Why can't I set the default drop-down option when I retrieve the data from the database?

Was it helpful?

Solution

Posting my comment as an answer as requested since it solved the problem.

All of the calls on a $resource or via the $http service object are done asynchronously since they are network calls and it's indeterminate how long it will take to get a response (if it were synchronous no other code would execute while the request was being made which is undesirable).

The fix is to just move the code that is expecting to use the data for initialization into the callback for the async function call. The callback is called as soon as response from the server is retrieved (after running the response through any interceptors you define)

Long story short in this case move this bit of code

$scope.filterItem = {
  discipline: $scope.results.disciplines[0]
};

Into the callback after the $scope.results has been assigned.

If you use $http (like $http.get(url) or $http.post(data,url)) the calls return an HTTPPromise so you can use success and error handler functions on the promise to get the data.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top