Reputation: 15715
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({});
};
}
Upvotes: 5
Views: 171
Reputation: 15715
Ok here is my final solution. I realized that I can access the ng-repeat scope from the controller, by passing the repeat item as a function parameter in ng-change:
HTML:
<div ng-controller="MyCtrl">
<div ng-repeat="row in rows">
<select ng-options="option.value as option.title for option in select1options" ng-model="row.select1" ng-change="updateSelect2(row.select1, row)"></select>
<select ng-options="option.value as option.title for option in row.options" ng-model="row.select2"></select>
</div>
<a ng-click="addRow()">Add Row</a>
</div>
JS:
function MyCtrl($scope) {
$scope.rows = [{options:[]}];
$scope.select1Options = [
{title: 'Option 1', value: '1'},
{title: 'Option 2', value: '2'},
{title: 'Option 3', value: '3'}
];
$scope.updateSelect2 = function(val, scope) {
if (val === '1') {
scope.options = [ //<-- this scope is the ng-repeat item's scope, from the function parameter
{title: 'A', value: 'A'},
{title: 'B', value: 'B'}
];
} else if (val === '2') {
scope.options = [
{title: 'AA', value: 'AA'},
{title: 'BB', value: 'BB'}
];
} else {
scope.options = [
{title: 'AAA', value: 'AAA'},
{title: 'BBB', value: 'BBB'}
];
}
};
$scope.addRow = function() {
$scope.rows.push({options:[]});
};
}
Note1: In the $scope.rows
array I had to pre add an 'options' array to each of the objects.
Note2: in $scope.updateSelect2
the scope
parameter refers to the ng-repeat item's scope (in this case row
), and it's not $scope
!
Upvotes: 1
Reputation: 5357
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'}
];
}
};
Upvotes: 3