Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Displaying list of options based on another select in Angular

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

like image 301
iiminov Avatar asked Jun 04 '15 08:06

iiminov


1 Answers

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

like image 142
adamjld Avatar answered Oct 21 '22 21:10

adamjld