javascript - Cascading parent child select boxes from dynamic JSON data -
i've created chained select-boxes dynamically json data receive server. chaining/cascading works in way every select-box named object following properties:
- parent attribute: name of object parent of select-box object.
options: array of option objects, each object contains: (a) option value (b) parent option value - parent select-box value current value mapped. (c) option id.
selected option: object 2 properties: (a) selected value (b) id of selected value.
i creating select-boxes using ng-repeat in "option" tag, or using ng-option in "select" tag, , using custom filter filter retrieved options (2) matching parent option value (2 > b) of option values (2 > a) "currently selected value" (3 > a) of parent object. doing many-to-one mapping child option values selected parent value using custom filter.
i able correctly map parent-child select-boxes, issue when change parent select-box value, "selected option value" of child object doesn't update (the child selected item doesn't grab first item in filtered list, causing grandchild drop-down not update.)[1]
is there way if parent value changes, child select-box (and subsequent children/grandchildren) initialized first option value instead of current blank value?
here working plunker. (ng-repeat implementation). appreciate help.
here another plunker ng-options implementation.
html (ng-repeat):
<div ng-repeat="selection in vm.selectiondata"> <div ng-repeat="(key, attribute) in selection.attributes"> <span>{{key}}</span> <select class="form-control" ng-model="attribute.selectedoption.name"> <option ng-repeat="option in attribute.options | optionfilter : selection.attributes[attribute.parentattr]">{{option.name}}</option> </select> </div> </div>
html (ng-options):
<div ng-repeat="selection in vm.selectiondata"> <div ng-repeat="(key, attribute) in selection.attributes"> <span>{{key}}</span> <select ng-model="attribute.selectedoption" ng-options="attribute.name attribute in (attribute.options | optionfilter : selection.attributes[attribute.parentattr]) track attribute.id"> </select> </div> </div>
js:
myapp.filter('optionfilter', function() { return function(items, parent) { var result = []; if (parent) { (var = 0; < items.length; i++) { console.log(items[0].parent, parent.selectedoption.name); if (items[i].parent === parent.selectedoption.name) { result.push(items[i]); } } return result; } else { return items; } } }); myapp.controller("myctrl", function($scope) { this.selectiondata = [{ selectiontype: "geography", attributes: { country: { parentattr: "none", options: [{ name: "india", parent: "none", id: 1 }, { name: "bangladesh", parent: "none", id: 2 }, { name: "afganistan", parent: "none", id: 3 }], selectedoption: { name: "india", id: 1 } }, state: { parentattr: "country", options: [{ name: "rajasthan", parent: "india", id: 1 }, { name: "haryana", parent: "india", id: 2 }, { name: "dhaka", parent: "bangladesh", id: 3 }, { name: "kabul", parent: "afganistan", id: 4 }], selectedoption: { name: "rajasthan", id: 1 } }, city: { parentattr: "state", options: [{ name: "kota", parent: "rajasthan", id: 1 }, { name: "sirsa", parent: "haryana", id: 2 }, { name: "alwar", parent: "rajasthan", id: 3 }, { name: "gurgaon", parent: "haryana", id: 4 }, { name: "kabul", parent: "kabul", id: 5 },{ name: "dhaka", parent: "dhaka", id: 6 } ], selectedoption: { name: "kota", id: 1 } } }, }]; });
references:
after struggling time, came solution (though not sure if conforms best practices). in custom filter returns filtered options based on parent object's selected option value, additionally sending current select box object. then,
- the filter first checks whether parent object exists or not, else returns options.
- if parent exists, loops through available options of current select-box object.
- if current select-box options' parent value matches parent object's selected option value, pushes filtered option values in result array, only if parent object's selected option not null (parent object's selected option can go null when grandparent value changed , parent not grab resulted filtered options, leading blank first option in parent select-box). temporarily cause current-select box empty, parent object's selected option null.
- then, checks whether current select-box object's selected option null. if so, assigns first element (object) of result array selected option object, , returns result array. since filter run select-boxes (grandparent, parent , child), set first element in parent's filtered array parent object's selected option. when parent object's selected option no longer null, current select-box show filtered options (from result array) , first element of result array assigned selected option of current select-box.
working demo here. please share if there better solution. below custom filter:
myapp.filter('optionfilter', function() { return function(items, parent, self) { var result = []; if (parent) { (var = 0; < items.length; i++) { if (parent.selectedoption !== null && items[i].parentvalue === parent.selectedoption.value) { result.push(items[i]); } } if (self.selectedoption === null) { self.selectedoption = result[0]; } return result; } else { return items; } } });
html:
<div ng-repeat="(key, item) in data"> <span>{{key}}</span> <select ng-model="item.selectedoption" ng-options="option.value option in (item.availableoptions | optionfilter : data[item.parent] : item) track option.id"> </select> </div>
data:
this.data = { country: { parent: "none", availableoptions: [{ value: "united states", parentvalue: "none", id: 1 }, { value: "china", parentvalue: "none", id: 2 }, { value: "india", parentvalue: "none", id: 3 }], selectedoption: { value: "united states", parentvalue: "none", id: 1 } }, state: { parent: "country", availableoptions: [{ value: "california", parentvalue: "united states", id: 1 }, { value: "shanghai", parentvalue: "china", id: 2 }, { value: "delhi", parentvalue: "india", id: 3 }], selectedoption: { value: "california", parentvalue: "united states", id: 1 } }, city: { parent: "state", availableoptions: [{ value: "greenfield", parentvalue: "california", id: 1 }, { value: "shanghai", parentvalue: "shanghai", id: 2 }, { value: "new delhi", parentvalue: "delhi", id: 3 }], selectedoption: { value: "greenfield", parentvalue: "california", id: 1 } } };
Comments
Post a Comment