6

I'm attempting to create a chained/cascading drop-down (select elements) using AngularJS but I'm having difficulty filtering and updating the 'selected' properties with my object properties.

When the page first loads, the selected items are filtered and displaying in the drop-downs properly. Once I change the parent drop-down, the child selected item doesn't grab the first item in the filtered list, causing the grandchild drop-down to not update.

Any insight would be greatly appreciated and note that I have the parent/child/grandchild arrays separated (and not in sub-arrays) because I will eventually be pulling my data from separate spocs/tables in SQL. If there is an easy way to create the sub-arrays in JSON then I'd be willing to change the data structure.

Here's a link to a coded example

HTML

<div ng-controller="dropdownCtrl" >                    
  <div>
     <select 
       ng-model="selectedParentItem"                        
       ng-options="p.displayName for p in parentItems">                        
     </select>
  </div>
  <div>
     <select                                                    
       ng-model="selectedChildItem"                     
       ng-options="c.displayName for c in filteredArray | filter:{parentId:           
         selectedParentItem.id}">                        
     </select>
  </div>
  <div>
     <select                                                    
       ng-model="selectedGrandChildItem"                        
       ng-options="g.displayName for g in grandChildItems | filter:{parentId: 
         selectedChildItem.parentId}">                        
     </select>
  </div>
</div>

Controller

function dropdownCtrl($scope, filterFilter) {
$scope.parentItems = [
    {
        "id": 0,
        "displayName": "parent 00"
    },
    {
        "id": 1,
        "displayName": "parent 01"
    },
    {
        "id": 2,
        "displayName": "parent 02"
    }
  ];
$scope.selectedParentItem = $scope.parentItems[0];

$scope.childItems = [
    {
        "id": 0,
        "displayName": "child0 of 00",
        "parentId": 0
    },
    {
        "id": 1,
        "displayName": "child1 of 00",
        "parentId": 0
    },
    {
        "id": 2,
        "displayName": "child2 of 00",
        "parentId": 0
    },
    {
        "id": 3,
        "displayName": "child0 of 01",
        "parentId": 1
    },
    {
        "id": 4,
        "displayName": "child1 of 01",
        "parentId": 1
    },
    {
        "id": 5,
        "displayName": "child0 of 02",
        "parentId": 2
    }
];
$scope.filteredArray = [];
$scope.$watch("parentId", function (newValue) {
    $scope.filteredArray = filterFilter($scope.childItems, newValue);
    $scope.selectedChildItem = $scope.filteredArray[0];
},true);


$scope.grandChildItems = [
    {
        "id": 0,
        "displayName": "grandChild0 of 00",
        "parentId": 0
    },
    {
        "id": 1,
        "displayName": "grandChild1 of 00",
        "parentId": 0
    },
    {
        "id": 2,
        "displayName": "grandChild2 of 00",
        "parentId": 0
    },
    {
        "id": 3,
        "displayName": "grandChild0 of 01",
        "parentId": 1
    },
    {
        "id": 4,
        "displayName": "grandChild1 of 01",
        "parentId": 1
    },
    {
        "id": 5,
        "displayName": "grandChild0 of 02",
        "parentId": 2
    }
];
$scope.selectedGrandChildItem = $scope.grandChildItems[0];
}
Umur Kontacı
  • 35,403
  • 8
  • 73
  • 96
ShaunCL
  • 73
  • 1
  • 1
  • 5

1 Answers1

29

You don't need a watch on this.. its easier than that. Comment out the filter, then change your ng-option as shown below. note, your last filter looked like it is using the wrong parent id (does the thirddrop down box relate to its parent or grand parent?)

<select
    class="form-control"
    ng-model="selectedParentItem"
    ng-options="p.displayName for p in parentItems">
</select>

<select
    class="form-control"
    ng-model="selectedChildItem"
    ng-options="c.displayName for c in childItems | filter:{parentId: selectedParentItem.id}">
</select>

<select
    class="form-control"
    ng-model="selectedGrandChildItem"
    ng-options="g.displayName for g in grandChildItems | filter:{parentId: selectedChildItem.parentId}">
</select>
Xevi Pujol
  • 557
  • 3
  • 14
sasonic
  • 764
  • 6
  • 13
  • That's how I had my child drop-down previously and instead of having the 'filteredArray' array, I used $scope.selectedChildItem = $scope.childItems[0]. This produces the same result as my original but I would like to have the first item in the filtered list to be assigned $scope.selectedChildItem. – ShaunCL Sep 10 '13 at 16:34
  • Not sure I follow what you are saying... you want something like this? [link](http://jsfiddle.net/2uh3Q/1/) This is dependant on first item in all three arrays go together for your default option. – sasonic Sep 10 '13 at 16:55
  • Sorry for the confusion. Ultimately, I want any "child" drop-downs to filter AND select the first item in the filtered list whenever a parent drop-down changes. My jsFiddle example does the filtering correctly but leaves the child drop-down blank instead of displaying the first item. Ex. change parent drop-down from 'parent 00' to 'parent 01.' The drop-down to the right has filtered its original array to 'child0 of 01' and 'child1 of 01' but the initial selection is blank. I want 'child0 of 01' to be selected so the granchild dropdown will also filter (and select 'grandChild0 of 01'). – ShaunCL Sep 10 '13 at 17:10
  • [Example I tried to mirror](http://stackoverflow.com/questions/16867093/angularjs-first-in-array-after-filter) but doesn't work – ShaunCL Sep 10 '13 at 17:12
  • oh okay, then back to the watch. sorry for the circle here. Maybe this is it? [link](http://jsfiddle.net/2uh3Q/2/) – sasonic Sep 10 '13 at 20:57