7

I have two select dropdowns where options in the second select depend on what option is selected in the first select.

At the moment I am trying to figure out what way I should return my data from the server which would depend on the way I setup my filter(s).

I would appreciate some input or suggestion on what the best practices when it comes to filtering data structures using multiple select dropdown's.

Just in case this is of interest to someone I am developing/testing with currently stable version of AngularJS (v1.3.15).

Data struct 1 - nested:

$scope.optionObjs = [
    {
        id: 1, name: 'option 1', desc: '',
        elements: [
            { id: 9, name: 'option 11', desc: '', },
            { id: 10, name: 'option 12', desc: '', },
            { id: 11, name: 'option 13', desc: '', },
            { id: 12, name: 'option 14', desc: '', },
            { id: 13, name: 'option 15', desc: '', },
        ],
    },
];

I was hoping to utilise angular filter like like the following example in my html but that didn't seem to work.

<select data-ng-model="firstSelect" data-ng-options="option.name for option in optionObjs"></select>

<select data-ng-model="secondSelect" data-ng-options="option.elements.name for option in optionObjs | filter:firstSelect"></select>

Update:

OK, this is super silly of me. All it took for the above data structure to adhere to my requirements is simple change to second select html (no custom filter function required).

<select data-ng-model="firstSelect" data-ng-options="option.name for option in optionObjs"></select>

<select data-ng-model="secondSelect" data-ng-options="option.name for option in firstSelect.elements"></select>

That is all. D'oh!!!

Data struct 2 - w/ parent reference:

$scope.optionObjs = [
    { id: 1, parent: null, name: 'option 1', desc: '', },
    { id: 9, parent: 1, name: 'option 11', desc: '', },
    { id: 10, parent: 1, name: 'option 12', desc: '', },
    { id: 11, parent: 1, name: 'option 13', desc: '', },
    { id: 12, parent: 1, name: 'option 14', desc: '', },
    { id: 13, parent: 1, name: 'option 15', desc: '', },
];

Going forward with this example I would have to write a filter for the first select to display only those options which have no parent reference.

<select data-ng-model="firstSelect" data-ng-options="option.name for option in optionObjs | filter:parent=null"></select>

<select data-ng-model="secondSelect" data-ng-options="option.elements.name for option in optionObjs | filter:firstSelect"></select>

Update:

Taking into account suggestion by @adamjld and experimenting some more with Angular filter I have come up with the following html update to go along with above data structure (no custom filter function required).

<select data-ng-model="firstSelect" data-ng-options="option.name for option in optionObjs | filter : { parent: null, }"></select>

<select data-ng-model="secondSelect" data-ng-options="option.elements.name for option in optionObjs | filter : { parent: firstSelect.id, }"></select>

While this is much simpler solution there is a slight problem with this on initial load. Because I do not initialise firstSelect as a scoped object in my controller second select box allows users to select any option they want. But As soon as an option is selected in first select box second select box options get filtered and only corresponding options to (parent) firstSelect.id are displayed.

References

Just in case people start complaining that I didn't utilise search at all here are some references: angular filter
ng-repeat :filter by single field

Community
  • 1
  • 1
iiminov
  • 969
  • 1
  • 15
  • 34
  • You can create a custom filter for the second dropdown, pass in the value from the first and return the relevant options. – adamjld Jun 04 '15 at 08:04
  • Thats exactly what I am working on right now but I would like to keep my data structure as a single object. – iiminov Jun 04 '15 at 09:01

2 Answers2

4

I think this will do what you are looking for.. I edited the data to show it working a bit better. I split your data into two arrays, a parent and child.

$scope.parentOptionObjs = [{
        id: 1,
        name: 'option 1',
        desc: ''
    }, {
        id: 2,
        name: 'option 2',
        desc: ''
    }];

$scope.childOptionObjs = [{
        parent: 1,
        id: 9,
        name: 'option 11',
        desc: ''
    }, {
        parent: 1,
        id: 10,
        name: 'option 12',
        desc: ''
    }, {
        parent: 1,
        id: 11,
        name: 'option 13',
        desc: ''
    }, {
        parent: 2,
        id: 12,
        name: 'option 14',
        desc: ''
    }, {
        parent: 2,
        id: 13,
        name: 'option 15',
        desc: ''
    }];
});

The children are now filtered by the id of the parent using the following filter.

app.filter('secondDropdown', function () {
    return function (secondSelect, firstSelect) {
        var filtered = [];
        if (firstSelect === null) {
            return filtered;
        }
        angular.forEach(secondSelect, function (s2) {
            if (s2.parent == firstSelect) {
                filtered.push(s2);
            }
        });
        return filtered;
    };
});

Fiddle

adamjld
  • 310
  • 1
  • 9
  • Yes, I was working on custom filter but this gives me an idea of how to keep things as a single structure. – iiminov Jun 04 '15 at 09:06
  • Are there any performance implications in keeping data structures as a single object or splitting it into two objects? – iiminov Jun 04 '15 at 09:13
  • Nope. You are better off keeping them split as they are easier to read in the code and then implement in situations like this. That would be my personal preference anyway, I sure there would be others who would argue the opposite. – adamjld Jun 04 '15 at 09:15
  • I am not really concerned about readability as options will be requested (using some kind of ajax pre-load) from the database. I just need to finalise the structure in which data is returned so that my select boxes work as intended. – iiminov Jun 04 '15 at 10:33
  • After reading up in Angular filter and thinking about it some more I managed to come with solution to both of my data structures which do not require custom filter function in my controller. @adamjld thank you very much for the help. – iiminov Jun 04 '15 at 11:18
0

Set an ng-model on first drop-down:

select ng-model="drp1Value"  

In the second drop-down:

select ng-disabled= "drp1Value == null"
Nimantha
  • 6,405
  • 6
  • 28
  • 69
shiva reddy
  • 417
  • 4
  • 9