1

I'm trying to get this code to provide a value in my select ng-options:

<select ng-model="selectedMovieId" ng-if="movies.length>0" ng-options="movie.id as movie.title for movie in movies track by movie.id"></select>
  <div>
    {{selectedMovieId||'No movie selected'}}
  </div>

But I never see a value for selectedMovieId. I've tried adding a dot to the ng model (something like foo.selectedMovieId) but I keep getting errors.

Having read 3-4 questions on this I feel like it has to be something simple I'm missing.

Here's my full code:

var app = angular.module("movieApp", []);

app.controller("movieCtrl", ["$scope", "$http", function($scope, $http) {
  $scope.apiKey = ''
  var baseUrl = 'https://api.themoviedb.org/3/'
  $scope.movies = []
  $scope.searchMovie = function() {
    var url = baseUrl + 'search/movie?api_key=' + $scope.apiKey + '&query=' + $scope.queryString;
    $http.get(url)
      .then(function(response) {
        $scope.movies = response.data.results;
      }, function() {
        console.log("some error");
      })
  }
  $scope.getCredits = function() {
    var url = baseUrl + 'movie/' + $scope.selectedMovieId + '/credits?api_key=' + $scope.apiKey
    console.log(url)
    console.log($scope.movies)
      /*$http.get(url)
          .then(function(response) {
              console.log(response.data)
              $scope.actors = response.data.results;
          }, function() {
              console.log("some error");
          })*/
  }
}]);

and html:

<div ng-app="movieApp" ng-controller="movieCtrl">
  <input type='text' ng-model='queryString' ng-submit="searchMovie()">
  <button ng-click="searchMovie()">
    Search
  </button>
  <hr/>
  <select ng-model="selectedMovieId" ng-if="movies.length>0" ng-options="movie.id as movie.title for movie in movies track by movie.id">
  </select>
  <div>
    {{selectedMovieId||'No movie selected'}}
  </div>
  <button ng-if="movies.length>0" ng-click="getCredits()">
    Get Credits
  </button>
</div>

And the jsfiddle I've been working in. Why won't the ng-model update?

AncientSwordRage
  • 7,086
  • 19
  • 90
  • 173
  • demo doesn't load any movies to even display your select. How are we supposed to assess what's going on? Note .... *always always always* use object in `ng-model` – charlietfl Feb 07 '16 at 23:59
  • That's because I've removed the API key. I'll try again to use an object as the `ng-model`, but I've only ever been stung when that overlapped with the name in the `ng-repeat` scope. – AncientSwordRage Feb 08 '16 at 00:02
  • 1
    But you aren't realizing that `ng-if` creates child scope and that is likely your whole problem. i bet using object resolves issue – charlietfl Feb 08 '16 at 00:04
  • @charlietfl you're right - I'm not realising that. I'll give it another go in the morning. Thanks. – AncientSwordRage Feb 08 '16 at 00:10

2 Answers2

3

Demo doesn't work without some data provided however I suspect your problem is breaking the golden rule of always using an object in ng-model

ng-if creates a child scope and child scopes will break 2 way bindings on primitives like you are currently doing

Set an object in controller so inheritance will work with subsequent child scopes and then in view bind ng-model to that object

charlietfl
  • 170,828
  • 13
  • 121
  • 150
1

The answer of @charlietfl was spot on. ng-if created a child scope so you won't be able to access your selectedMovieId like that.

If for some reason you need to use primitive types for binding, you can change your binding as following (this is just a workaround)

<select ng-model="$parent.selectedMovieId" ng-if="movies.length>0" ng-options="movie.id as movie.title for movie in movies track by movie.id">
  </select>

It will work because it's using the implicit $parent attribute of the current $scope.

Read more:

  1. Understanding scopes
Mr. Duc Nguyen
  • 1,049
  • 7
  • 16
  • 2
    using `$parent` is a code smell ... Best practices suggest setting object in controller. If a change is made to put another child scope in the middle you can rely on inheritance but your approach would mean adding `$parent.$parent` which gets ugly to test – charlietfl Feb 08 '16 at 00:21
  • Yes. It's ugly, and things can become messy and crazy with it in the HTML template. The only "good" reason I've ever had to use it was when dealing with tiny templates that including other templates (also tiny) using ng-include. They were really small that using $parent became very clear where it pointed to – Mr. Duc Nguyen Feb 08 '16 at 00:46
  • pointing at a controller object is pretty clear too and doesn't require figuring out what the parent chain is. Best practices suggest that all models should be objects anyway – charlietfl Feb 08 '16 at 00:47