Tyler
Tyler

Reputation: 3813

angularjs ng-repeat dependent on another ng-repeat

I have an array (helper.makes) like so:

[0] => { make: 'BMW', models: ['3 series','5 series'] }
[1] => { make: 'Honda', models: ['Camry','Corolla'] }

In my select I want the user to select make and then the model select will update accordingly. Here is my code so far:

<label>
  <p>Make</p>
  <select ng-model="make">
    <option ng-repeat="(key, value) in helper.makes | orderBy: 'name'">{{ value.name }}</option>
  </select>
</label>
<label>
  <p>Model</p>
  <select ng-model="model">
    <option ng-repeat="(key, value) in helper.getModelByMake(make) | orderBy: value">{{ value }}</option>
  </select>
</label>

Before I simply used an associative array so I could do helper.makes[make] but that kept turning it into an object and angular refused to order it. Doing it this way I created the function getModelByMake which simply loops through the list of makes, finds the right one and returns it's models array.

The problem is, that does not seem to update as the person changes the make. I believe it is attempting to load once, seeing that no make is selected and returning blank results.

What method would be best for such an instance in AngularJS? Is there something awesome AngularJS can do here that I am unaware of?

Upvotes: 0

Views: 731

Answers (2)

developer033
developer033

Reputation: 24894

First of all, I extremely recommend you to use ngOptions instead of ngRepeat. ngOptions was made exactly for this kind of things.

Also, you don't need to use ngChange directive or $watch, you just need to get the models array from the ngModel selected in the first ngOptions, as below:

var app = angular.module('app', [])

.controller('mainCtrl', function($scope) {
  $scope.makes = [  
     {  
        "make":"BMW",
        "models":[  
           "3 series",
           "5 series"
        ]
     },
     {  
        "make":"Honda",
        "models":[  
           "Camry",
           "Corolla"
        ]
     }
  ];
});
<!DOCTYPE html>
<html ng-app="app">

<head>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular.min.js"></script>
</head>

<body ng-controller="mainCtrl">
  <label>
    <p>Make</p>
    <select ng-model="make" ng-options="objMake as objMake.make for objMake in makes">
    </select>
  </label>
  <div ng-if="make">
    <label>
      <p>Model</p>
      <select ng-model="model" ng-options="model for model in make.models">
      </select>
    </label>
  </div>
</body>

</html>

Note: I used ng-if no hide the second select when the first select has no selection.

Upvotes: 2

currarpickt
currarpickt

Reputation: 2302

You could use ng-change in the make option and create something like this:

<label>
  <p>Make</p>
  <select ng-model="make">
    <option ng-repeat="(key, value) in helper.makes | orderBy: 'name'" ng-change="getModelByMake()">{{ value.name }}</option>
  </select>
</label>
<label>
  <p>Model</p>
  <select ng-model="model">
    <option ng-repeat="(key, value) in helper.model | orderBy: value">{{ value }}</option>
  </select>
</label>

Then in your getModelByMake() function, you get the make ID and get the models.

Upvotes: 1

Related Questions