KnockoutJS - 将输入值与数据列表值相关联 [英] KnockoutJS - Linking value from a input to a datalist value
问题描述
我正在根据ko observable生成 datalist
选项。
I'm generating a datalist
options based on a ko observable.
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>
好的,这是交易:在公司
function,我存储该公司的Id。我想做的事?能让我将Id值链接到selectedCompany变量而不是名称的东西?我想显示name属性,但我需要存储Id。
Ok, here's the deal: in the Company
function, I store the Id from that company. What I want to do? Something that able me to link the Id value to selectedCompany variable instead the name? I want to display the name property, but I need to store the Id.
有没有办法做到这一点?
谢谢大家!
Is there a way to do this? Thank you all!
推荐答案
我想显示名称属性,但是我需要存储Id。
I want to display the name property, but I need to store the Id.
由于目前没有针对HTML5的Knockout绑定< datalist>
,我做了一个。
Since there is currently no Knockout binding for HTML5 <datalist>
, I made one.
我试图从选择
尽可能多地借款绑定,因此支持选项
, optionsText
和 optionsValue
。您可以通过 value
指定目标可观察对象。
I tried to borrow as much as I could from the select
binding, so there is support for options
, optionsText
and optionsValue
. You can specify a target observable via 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");
}
};
})();
我希望我能做到这一点。我们欢迎更正和改进建议。
I hope I got most of this right. Corrections and improvement suggestions are welcome.
您可以这样使用它:
<input list="company" data-bind="datalist: {
options: companies,
optionsValue: 'id',
optionsText: 'name',
value: selectedCompany
}" />
注意。
- 无需在HTML中创建单独的
< datalist>
。自定义绑定为您完成此操作。 - 但是,您必须提供
list =
属性< input>
元素。到目前为止,我发现在JavaScript中无法动态设置它。 -
value
是可选的,但是如果你提供它,它必须是一个可观察的。 - 您仍然可以在
datalist
值绑定>。它将包含< input>
显示的任何文本(没有惊喜)。但是,写入内置值也会更新datalist
值,反之亦然。 -
datalist
值具有优先权,并将覆盖视图模型init上的内置值。之后它们保持同步。 -
选项
应该是一个对象的数组(普通的或可观察的) - 本例中的公司) 。 -
optionsText
和optionsValue
是应映射到您的属性的字符串选项。 - 您不必使用
optionsValue
- 在这种情况下,整个对象(单个公司)将存储在值
。我希望仅存储ID。 - 目前,设置会对
更改
事件作出反应。这意味着在您离开输入字段之前,您的视图模型不会更新。 - 在Chrome 32,YMMV上测试。正如我所说,欢迎提出意见和更正。
- There is no need to create a separate
<datalist>
in the HTML. The custom binding does that for you. - You must, however, supply the
list=""
attribute of the<input>
element. I found no way of dynamically setting that in JavaScript so far. value
is optional, but if you supply it, it must be an observable.- You can still use the original
value
binding outside ofdatalist
. It will contain whatever text the<input>
displays (no surprises there). However, writing to the built-in value also updates thedatalist
value, and the other way around. - The
datalist
value has precedence and will overwrite the built-in value upon view model init. After that they stay in sync. options
should be an array (plain old or observable) of objects — companies in this case).optionsText
andoptionsValue
are strings that should map to properties on your options.- You do not have to use
optionsValue
— in that case the entire object (a single company) would be stored invalue
. I would prefer that over storing only the ID. - Currently the set-up reacts to the
change
event. That means your view model won't update until you leave the input field. - Tested on Chrome 32, YMMV. As I said, comments and corrections are welcome.
这是一个小提琴,显示了这一点:http://jsfiddle.net/GJ4h4/3/
Here is a fiddle that shows this: http://jsfiddle.net/GJ4h4/3/
这篇关于KnockoutJS - 将输入值与数据列表值相关联的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!