我在knockoutjs网站上找到了样本。这里它们是多重选择列表框的绑定值。但他们使用的是非常简单的可观察数组。 availableCountries 和 selectedCountries 。
<p>
Choose some countries you'd like to visit:
<select data-bind="options: availableCountries, selectedOptions: chosenCountries" size="5" multiple="true"></select>
</p>
<script type="text/javascript">
var viewModel = {
availableCountries : ko.observableArray(['France', 'Germany', 'Spain']),
chosenCountries : ko.observableArray(['Germany']) // Initially, only Germany is selected
};
// ... then later ...
viewModel.chosenCountries.push('France'); // Now France is selected too
</script>
但是我的模型太复杂了,我的模型中提到了json格式。
"JobOrderDelivTranscript" : [{
"TranscriptType" : {
"Id" : 1,
"Name" : null,
"CreatedBy" : 0,
"CreatedDate" : "0001-01-01T00:00:00",
"ModifiedBy" : 0,
"ModifiedDate" : "0001-01-01T00:00:00",
"IsActive" : false,
"EntityStatus" : 0,
"ErrorMessage" : null,
"ExternalID" : 0,
"ExternalSystemID" : 0
},
"Id" : 1,
"Name" : null,
"CreatedBy" : 0,
"CreatedDate" : "0001-01-01T00:00:00",
"ModifiedBy" : 0,
"ModifiedDate" : "0001-01-01T00:00:00",
"IsActive" : false,
"EntityStatus" : 0,
"ErrorMessage" : null,
"ExternalID" : 0,
"ExternalSystemID" : 0
}, {
"TranscriptType" : {
"Id" : 2,
"Name" : null,
"CreatedBy" : 0,
"CreatedDate" : "0001-01-01T00:00:00",
"ModifiedBy" : 0,
"ModifiedDate" : "0001-01-01T00:00:00",
"IsActive" : false,
"EntityStatus" : 0,
"ErrorMessage" : null,
"ExternalID" : 0,
"ExternalSystemID" : 0
},
"Id" : 2,
"Name" : null,
"CreatedBy" : 0,
"CreatedDate" : "0001-01-01T00:00:00",
"ModifiedBy" : 0,
"ModifiedDate" : "0001-01-01T00:00:00",
"IsActive" : false,
"EntityStatus" : 0,
"ErrorMessage" : null,
"ExternalID" : 0,
"ExternalSystemID" : 0
}
]
这里我的“ selectedCountries ”将是JobOrderDelivTranscript()。如果我选择第一个选项,则应使用JobOrderDelivTranscript()[0] .TranscriptType.Id进行映射。在他们的例子中,他们使用字符串数组,但我必须绑定复杂的数据。我怎么能这样做。
即使我尝试使用自定义绑定
ko.bindingHandlers['selectedCustomOptions'] = {
getSelectedValuesFromSelectNode: function (selectNode) {
var result = [];
var nodes = selectNode.childNodes;
for (var i = 0, j = nodes.length; i < j; i++) {
var node = nodes[i], tagName = ko.utils.tagNameLower(node);
if (tagName == "option" && node.selected)
result.push(ko.selectExtensions.readValue(node));
else if (tagName == "optgroup") {
var selectedValuesFromOptGroup = ko.bindingHandlers['selectedCustomOptions'].getSelectedValuesFromSelectNode(node);
Array.prototype.splice.apply(result, [result.length, 0].concat(selectedValuesFromOptGroup)); // Add new entries to existing 'result' instance
}
}
return result;
},
'init': function (element, valueAccessor, allBindingsAccessor) {
ko.utils.registerEventHandler(element, "change", function () {
var value = valueAccessor();
var valueToWrite = ko.bindingHandlers['selectedCustomOptions'].getSelectedValuesFromSelectNode(this);
ko.jsonExpressionRewriting.writeValueToProperty(value, allBindingsAccessor, 'value', valueToWrite);
});
},
'update': function (element, valueAccessor) {
if (ko.utils.tagNameLower(element) != "select")
throw new Error("values binding applies only to SELECT elements");
var newValue = ko.utils.unwrapObservable(valueAccessor());
if (newValue && typeof newValue.length == "number") {
var nodes = element.childNodes;
for (var i = 0, j = nodes.length; i < j; i++) {
var node = nodes[i];
if (ko.utils.tagNameLower(node) === "option")
ko.utils.setOptionNodeSelectionState(node, arrayIndexOf(newValue, ko.selectExtensions.readValue(node)) >= 0);
}
}
}
};
function arrayIndexOf (array, item) {
if (typeof Array.prototype.indexOf == "function")
return Array.prototype.indexOf.call(array, item);
for (var i = 0, j = array.length; i < j; i++)
if (array[i].TranscriptType.Id() === item.Id)
return i;
return -1;
}
我已经选择了选项,但json数据没有得到更新。
有什么简单的方法吗?
提前致谢。
答案 0 :(得分:1)
我不是100%我理解你的问题,但似乎你试图用selectedOptions绑定绑定到一个复杂的对象。有两种方法可以做你想要的。第一种是使用optionsValue绑定结合计算器将您的绑定id拉到对象根级别(不幸的是,optionsValue绑定仅在根目录下工作,因此optionsValue: 'TranscriptType.Id'
不起作用。)
<p>Choose some countries you'd like to visit:</p>
<select data-bind="options: availableCountries, optionsText: optionsText,
optionsValue: 'id', selectedOptions:
chosenCountries" size="5" multiple="true"></select>
<p data-bind="text: ko.toJSON(chosenCountries)">
</p>
var JobOrderDelivTranscript = function(id) {
var self = this;
this.TranscriptType = {
Id : id
}
this.id = ko.computed(function() {
return self.TranscriptType.Id
});
};
http://jsfiddle.net/madcapnmckay/6K6kH/
第二种方法是不使用optionsValue,在这种情况下,KO将使用对象引用来测试相等性。只要你在selectedCounties数组中保留相同的对象引用,一切都会有效。
var viewModel = function () {
var self = this;
this.availableCountries = ko.observableArray([
new JobOrderDelivTranscript("Some Transcript 1"),
new JobOrderDelivTranscript("Some Transcript 2"),
new JobOrderDelivTranscript("Some Transcript 3")]);
this.chosenCountries = ko.observableArray([ self.availableCountries()[0] ]);
this.optionsText = function(option) {
return option.TranscriptType.Id;
};
};
var vm = new viewModel();
vm.chosenCountries.push(vm.availableCountries()[1]);
http://jsfiddle.net/madcapnmckay/hmsqf/
两种方式都有优点和缺点,这取决于你的特殊情况,这是正确的。
修改强>
要使用映射插件执行相同操作,您需要使用文档here under "Advanced Usage"中涵盖的映射选项。
这是一个你应该能够适应的例子。
http://jsfiddle.net/madcapnmckay/hmsqf/2/
为了更好地构建代码,我建议创建许多javascript类,就像我在示例中所做的那样,这允许逻辑包含在descrete块中。我也不建议使用旧的jquery选择器,许多KO的初学者认为可以将两者混合使用。在我看来,它削弱了视图模型和视图之间的关注点分离。为什么在使用$(selector).click
绑定时使用click
。
希望这有帮助。