Search code examples
javascriptangularjsangularjs-scopeng-options

chained select within ng-repeat


I'm having trouble figuring out scoping within ng-repeat. I want to create chained selects, and I want to keep each row in the ng-repeat to exist separately in separate scopes. Currently changing the first select in any of the rows will change the second selects in all of the rows.

(Real life example: I have a form where I have to add cars, first choose a 'Make', pull its 'Models' from an api, and show models in the second select. Users must be able to add any number of cars.)

HTML:

<div ng-controller="MyCtrl">
  <div ng-repeat="row in rows">
    <select ng-options="option.value as option.title for option in options1" ng-model="row.select1" ng-change="updateSelect2(row.select1)"></select> 
    <select ng-options="option.value as option.title for option in options2" ng-model="row.select2"></select>
  </div>
  <a ng-click="addRow()">Add Row</a>
</div>

JS:

function MyCtrl($scope) {
  $scope.rows = [{}];
  $scope.options1 = [
    {title: 'Option 1', value: '1'},
    {title: 'Option 2', value: '2'},
    {title: 'Option 3', value: '3'}
  ];

  $scope.options2 = [];

  $scope.updateSelect2 = function(val) {
    if (val === '1') {
      $scope.options2 = [
        {title: 'A', value: 'A'},
        {title: 'B', value: 'B'}
      ];
    } else if (val === '2') {
      $scope.options2 = [
        {title: 'AA', value: 'AA'},
        {title: 'BB', value: 'BB'}
      ];
    } else {
      $scope.options2 = [
        {title: 'AAA', value: 'AAA'},
        {title: 'BBB', value: 'BBB'}
      ];
    }
  };

  $scope.addRow = function() {
    $scope.rows.push({});
  };
}

FIDDLE HERE


Solution

  • You need to have the options2 part separated for each row.

    A simple solution will be to just save it inside the row object, but you might want a more elaborate data structure.

    Here is a simple example using your code.

    HTML:

    <div ng-repeat="row in rows">
      <select ng-options="option.value as option.title for option in options1" ng-model="row.select1" ng-change="updateSelect2(row.select1, $index)">  </select> 
      <select ng-options="option.value as option.title for option in row.options2" ng-model="row.select2"></select>
    </div>
    

    JS:

    $scope.updateSelect2 = function(val, index) {
      if (val === '1') {
        $scope.rows[index].options2 = [
          {title: 'A', value: 'A'},
          {title: 'B', value: 'B'}
        ];
      } else if (val === '2') {
        $scope.rows[index].options2 = [
          {title: 'AA', value: 'AA'},
          {title: 'BB', value: 'BB'}
        ];
      } else {
        $scope.rows[index].options2 = [
          {title: 'AAA', value: 'AAA'},
          {title: 'BBB', value: 'BBB'}
        ];
      }
    };