[英]KnockoutJS - Linking value from a input to a datalist value
我正在基于ko observable生成一个datalist
选项。
function Company(company) {
this.id = company.Id;
this.name = company.Name;
this.state = company.State.name;
}
var self = this;
self.companies = ko.observable();
$.get('...', {}, function(result) {
ko.utils.arrayForEach(result, function(company) {
self.companies.push(new Company(ko.toJS(company)));
});
});
HTML:
<input type="text" data-bind="value: selectedCompany" list="companiesList" />
<datalist id="companiesList" data-bind="foreach: companies">
<option data-bind="value: name, text: state"></option>
</datalist>
好的,这是交易:在Company
功能中,我存储该公司的Id。 我想做的事? 能够将Id值链接到selectedCompany变量而不是名称的东西? 我想显示name属性,但我需要存储Id。
有没有办法做到这一点? 谢谢你们!
我想显示name属性,但我需要存储Id。
由于HTML5 <datalist>
目前没有Knockout绑定,我做了一个。
我试图从select
绑定中尽可能多地借用,因此支持options
, optionsText
和optionsValue
。 您可以通过value
指定目标可观察对象。
ko.bindingHandlers.datalist = (function () {
function getVal(rawItem, prop) {
var item = ko.unwrap(rawItem);
return item && prop ? ko.unwrap(item[prop]) : item;
}
function findItem(options, prop, ref) {
return ko.utils.arrayFirst(options, function (item) {
return ref === getVal(item, prop);
});
}
return {
init: function (element, valueAccessor, allBindingsAccessor) {
var setup = valueAccessor(),
textProperty = ko.unwrap(setup.optionsText),
valueProperty = ko.unwrap(setup.optionsValue),
dataItems = ko.unwrap(setup.options),
myValue = setup.value,
koValue = allBindingsAccessor().value,
datalist = document.createElement("DATALIST");
// create an associated <datalist> element
datalist.id = element.getAttribute("list");
document.body.appendChild(datalist);
// when the value is changed, write to the associated myValue observable
function onNewValue(newVal) {
var dataItems = ko.unwrap(setup.options),
selectedItem = findItem(dataItems, textProperty, newVal),
newValue = selectedItem ? getVal(selectedItem, valueProperty) : void 0;
if (ko.isWriteableObservable(myValue)) {
myValue(newValue);
}
}
// listen for value changes
// - either via KO's value binding (preferred) or the change event
if (ko.isSubscribable(koValue)) {
koValue.subscribe(onNewValue);
} else {
ko.utils.registerEventHandler(element, "change", function () {
onNewValue(this.value);
});
}
// init the element's value
// - either via the myValue observable (preferred) or KO's value binding
if (ko.isObservable(myValue) && myValue()) {
element.value = getVal(findItem(dataItems, valueProperty, myValue()), textProperty);
} else if (ko.isObservable(koValue) && koValue()) {
onNewValue(koValue());
}
},
update: function (element, valueAccessor) {
var setup = valueAccessor(),
datalist = element.list,
dataItems = ko.unwrap(setup.options),
textProperty = ko.unwrap(setup.optionsText);
// rebuild list of options when an underlying observable changes
datalist.innerHTML = "";
ko.utils.arrayForEach(dataItems, function (item) {
var option = document.createElement("OPTION");
option.value = getVal(item, textProperty);
datalist.appendChild(option);
});
ko.utils.triggerEvent(element, "change");
}
};
})();
我希望我能做到最好。 欢迎更正和改进建议。
你会像这样使用它:
<input list="company" data-bind="datalist: {
options: companies,
optionsValue: 'id',
optionsText: 'name',
value: selectedCompany
}" />
笔记。
<datalist>
。 自定义绑定为您执行此操作。 <input>
元素的list=""
属性。 到目前为止,我发现在JavaScript中无法动态设置它。 value
是可选的,但是如果你提供它,它必须是一个可观察的。 datalist
之外的原始value
绑定。 它将包含<input>
显示的任何文本(没有惊喜)。 但是, 写入内置值也会更新datalist
值, datalist
。 datalist
值具有优先权,并将覆盖视图模型init上的内置值。 之后他们保持同步。 options
应该是一个对象的数组(普通的或可观察的) - 本例中的公司)。 optionsText
和optionsValue
是应映射到选项属性的字符串。 optionsValue
- 在这种情况下,整个对象(单个公司)将存储在value
。 我宁愿只存储ID。 change
事件作出反应。 这意味着在您离开输入字段之前,您的视图模型不会更新。 下面是一个从原始小提琴复制的演示。
function main() { function Company(company) { this.id = company.Id; this.name = company.Name; this.state = company.State.name; } function ViewModel(sampleData) { var self = this; self.companies = ko.observableArray(); ko.utils.arrayForEach(sampleData, function (companyData) { self.companies.push(new Company(companyData)); }); // KO's "value" binding _can_ supply a start value self.val = ko.observable("Microsoft"); // ... but it is overridden by datalist's "value" binding - in any case you can use both self.selectedCompany = ko.observable(1); } // ----------------------------------------------------------------------------------- ko.applyBindings(new ViewModel([{ Id: 1, Name: "Apple", State: { name: "California" } }, { Id: 2, Name: "Microsoft", State: { name: "Washington" } }, { Id: 3, Name: "IBM", State: { name: "New York" } }])); } // ----------------------------------------------------------------------------------- ko.bindingHandlers.datalist = (function () { function getVal(rawItem, prop) { var item = ko.unwrap(rawItem); return item && prop ? ko.unwrap(item[prop]) : item; } function findItem(options, prop, ref) { return ko.utils.arrayFirst(options, function (item) { return ref === getVal(item, prop); }); } return { init: function (element, valueAccessor, allBindingsAccessor) { var setup = valueAccessor(), textProperty = ko.unwrap(setup.optionsText), valueProperty = ko.unwrap(setup.optionsValue), dataItems = ko.unwrap(setup.options), myValue = setup.value, koValue = allBindingsAccessor().value, datalist = document.createElement("DATALIST"); // create an associated <datalist> element datalist.id = element.getAttribute("list"); document.body.appendChild(datalist); // when the value is changed, write to the associated myValue observable function onNewValue(newVal) { var dataItems = ko.unwrap(setup.options), selectedItem = findItem(dataItems, textProperty, newVal), newValue = selectedItem ? getVal(selectedItem, valueProperty) : void 0; if (ko.isWriteableObservable(myValue)) { myValue(newValue); } } // listen for value changes // - either via KO's value binding (preferred) or the change event if (ko.isSubscribable(koValue)) { koValue.subscribe(onNewValue); } else { ko.utils.registerEventHandler(element, "change", function () { onNewValue(this.value); }); } // init the element's value // - either via the myValue observable (preferred) or KO's value binding if (ko.isObservable(myValue) && myValue()) { element.value = getVal(findItem(dataItems, valueProperty, myValue()), textProperty); } else if (ko.isObservable(koValue) && koValue()) { onNewValue(koValue()); } }, update: function (element, valueAccessor) { var setup = valueAccessor(), datalist = element.list, dataItems = ko.unwrap(setup.options), textProperty = ko.unwrap(setup.optionsText); // rebuild list of options when an underlying observable changes datalist.innerHTML = ""; ko.utils.arrayForEach(dataItems, function (item) { var option = document.createElement("OPTION"); option.value = getVal(item, textProperty); datalist.appendChild(option); }); ko.utils.triggerEvent(element, "change"); } }; })(); main();
.hint { color: silver; font-size: 80%; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.0.0/knockout-min.js"></script> <input list="company" type="text" placeholder="Select a company..." data-bind="value: val, datalist: { options: companies, optionsValue: 'id', /* try removing 'optionsValue' and see what happens to the view model */ optionsText: 'name', value: selectedCompany }" /> <span class="hint">(note the "change" event occurs after the field loses focus!)</span> <hr /> <p>View Model:</p> <pre data-bind="text: ko.toJSON($root, null, 2)"></pre>
你想类似这样 ?
HTML
<select data-bind="options: companies, optionsText: 'state', value: selectedCompany, optionsCaption: 'Choose...' "></select>
<input type="text" data-bind="value: selectedCompany() ? selectedCompany().name : 'unknown'" />
JAVASCRIPT
var Company = function (company) {
this.id = company.Id;
this.name = company.Name;
this.state = company.State.name;
}
var viewModel = {
selectedCompany: ko.observable(),
companies: ko.observableArray()
};
for(var x = 0; x<5; x++){
viewModel.companies.push(new Company({Id: x, Name:'name' + x, State: { name: 'namestate' + x}}));
}
ko.applyBindings(viewModel);
Knockout已经有一些选项来创建这个选择..请参阅文档http://knockoutjs.com/documentation/options-binding.html
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.