how to populate an observable array from two different arrays in knockout.js -
within app have section allows users add filter search criteria filter observable array contains 3 drop down menus , input fields manually adding values. 2 of drop down menus static, third populated based upon selected items located elsewhere in page. having trouble in binding between 2 array's. have drop downs populating cannot figure out how pass value selectedattributes() array inserted in attribure property of filter list
html
<input type="button" value="add filter" title="add filter" data-bind="click: $root.addfilter, enable: myfilters().length < 10" /> <table> <tbody data-bind="foreach: myfilters"> <tr> <td> <!-- ko with: $root.iqreport --> <select data-bind="options: selectedattributes(), optionstext: function(selectedattributes){ return selectedattributes.namehierarchy() + '.' + selectedattributes.labelname() }, optionscaption:'select field...'"> </select> <!-- /ko --> </td> <td> <select data-bind="options: $root.filteroperators, value:operator, optionstext: 'operatorname'"> </select> </td> <td> <input data-bind="value: criteria1" /> </td> <td> <input data-bind="value: criteria2" /> </td> <td> <select data-bind="options: $root.joinoperators, value:joinoperator, optionstext: 'joinname'"> </select> </td> <td> <a class="attributelink" data-bind="click: $root.removefilter">remove</a> </td> </tr>
knockoutjs
function filterlist(joiningoperator, attributehierarchy, attributeidhierarchy, operator, filtercriteria, filtercriteriarange) { var self = this; self.joinoperator = ko.observable(joiningoperator); self.attribute = ko.observable(attributehierarchy); self.attributeid = ko.observable(attributeidhierarchy); self.operator = ko.observable(operator); self.criteria1 = ko.observable(filtercriteria); self.criteria2 = ko.observable(filtercriteriarange); } var viewmodel function(){ //non-editable operators self.filteroperators = [ { operatorname: "equals", operatorvalue: "=" }, { operatorname: "greater than", operatorvalue: ">" }, { operatorname: "greater or equal to", operatorvalue: ">=" }, { operatorname: "less than", operatorvalue: "<" }, { operatorname: "less or equal to", operatorvalue: "<=" }, { operatorname: "not equal to", operatorvalue: "<>" }, { operatorname: "not less than", operatorvalue: "!>" }, { operatorname: "not greater than", operatorvalue: "!<" }, { operatorname: "between", operatorvalue: "between" }, { operatorname: "like", operatorvalue: "like" } ]; //non-editable joins self.joinoperators = [ {joinname: "and"}, {joinname: "or"} ]; //define filter collection self.myfilters = ko.observablearray([]); //add new filter row self.addfilter = function () { self.myfilters.push(new filterlist(self.joinoperators[0], "", "", self.filteroperators[0], "", "")); }; filterlist.attribute.subscribe(function () { }, filterlist); self.removefilter = function (row) { self.myfilters.remove(row); }; }
the collection iqreports populated array independent of myfilters[] hence virtual binding in html.
what learn when user selects value selected attributes drop down how go having value populate/update observable property self.attribute
of myfilters
update
the iqreports collection observable array consisting of additional observable arrays.this created server side, , passed client. selectedattributes class contains following properties
public class reportentity { public int entityid { get; set; public string name { get; set; } public string iconpath { get; set; } public list<reportattribute> primaryattributes { get; set; } public list<reportattribute> secondaryattributes { get; set; } public list<reportassociatedentity> associatedentities { get; set; } public string hierarchy { get; set; } public string namehierarchy { get; set; } public reportentity() { // initialize attributes lists. primaryattributes = new list<reportattribute>(); secondaryattributes = new list<reportattribute>(); // initialize associated entities list. associatedentities = new list<reportassociatedentity>(); } } public class reportattribute { public string fieldname { get; set; } public string labelname { get; set; } public bool isprimary { get; set; } public int position { get; set; } public bool isselected { get; set; } public bool issortedby { get; set; } public int sortposition { get; set; } public bool sortascending { get; set; } public bool isgroupedby { get; set; } public string namehierarchy { get; set; } public string hierarchy { get; set; } public reportattribute() { } }
once in client can navigate values using firebug in manner self.iqreport().selectedattributes()[0]().fieldname
think reference getting lost because have nested inside of observable array (myfilters) why have virtual binding wrapped around section pertains iqreports. removing statement breaks foreach because cannot resolve property selectedattributes() trying explicitly path using $root not work resulting in none of drop downs being populated. firebug @ point state cannot find property selectedattributes().
the workaround introduced move iqreports reference out of foreach instead have in html
<!-- ko with: $root.iqreport --> <select data-bind="options: selectedattributes(), value: $root.selecteditem, optionstext: function(selectedattributes){ return selectedattributes.namehierarchy() + '.' + selectedattributes.labelname() }, optionscaption:'select field...'"> </select> <!-- /ko --> <input type="button" value="add filter" title="add filter" data-bind="click: $root.addfilter, enable: myfilters().length < 10" /> <!--<pre data-bind="text: ko.tojson(iqreport, null, 2)"></pre>--> <table> <tbody data-bind="foreach: myfilters"> <tr> <td> <b><span data-bind="text: filterattribute" /></b> </td> <td> <select data-bind="options: $root.filteroperators, value:operator, optionstext: 'operatorname'"> </select> </td> <td> <input data-bind="value: criteria1" /> </td> <td> <input data-bind="value: criteria2" /> </td> <td> <select data-bind="options: $root.joinoperators, value:joinoperator, optionstext: 'joinname'"> </select> </td> <td> <a class="attributelink" data-bind="click: $root.removefilter">remove</a> </td> </tr> </tbody> </table>
then within view model added new observable , setup mapping table follows
self.selecteditem = ko.observable(); //define filter collection self.myfilters = ko.observablearray([]); //add new filter row //here navigated individual field properties using selecteditem object self.addfilter = function () { self.myfilters.push(new filterlist(self.joinoperators[0], self.selecteditem().namehierarchy() + "." + self.selecteditem().fieldname(), "", self.filteroperators[0], "", "")); };
while not initial preferred approach provide workaround. using virtual binding allowed me populate select element never able pass value of select myfilters.attribute() observable. suspect due foreach have no idea how work around it
-cheers
use value
binding , bind self.attribute
, , remove with
binding value
binding can find self.attribute
.
so instead of this:
<!-- ko with: $root.iqreport --> <select data-bind=" options: selectedattributes(), optionstext: function(selectedattributes){ return selectedattributes.namehierarchy() + '.' + selectedattributes.labelname() }, optionscaption:'select field...' "> </select> <!-- /ko -->
do this:
<select data-bind=" options: $root.iqreport.selectedattributes(), optionstext: function(selectedattributes){ return selectedattributes.namehierarchy() + '.' + selectedattributes.labelname() }, optionscaption:'select field...', value: attribute ">
Comments
Post a Comment