KnockoutJS - 将输入值与数据列表值相关联

Kiw*_*nax 6 javascript html5 knockout.js html-datalist

我正在datalist基于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)));
    });
});
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

好的,这是交易:在Company函数中,我存储来自该公司的Id.我想做的事?能够将Id值链接到selectedCompany变量而不是名称的东西?我想显示name属性,但我需要存储Id.

有没有办法做到这一点?谢谢你们!

Tom*_*lak 11

我想显示name属性,但我需要存储Id.

由于目前没有针对HTML5的Knockout绑定<datalist>,我做了一个.

我试图从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");
        }
    };
})();
Run Code Online (Sandbox Code Playgroud)

我希望我能做到最好.欢迎更正和改进建议.

你会像这样使用它:

<input list="company" data-bind="datalist: {
    options: companies, 
    optionsValue: 'id', 
    optionsText: 'name', 
    value: selectedCompany
}" />
Run Code Online (Sandbox Code Playgroud)

笔记.

  • 无需<datalist>在HTML中创建单独的内容.自定义绑定为您执行此操作.
  • 但是,您必须提供元素的list=""属性<input>.到目前为止,我发现在JavaScript中无法动态设置它.
  • value 是可选的,但是如果你提供它,它必须是一个可观察的.
  • 你仍然可以使用value外面的原始绑定datalist.它将包含<input>显示的任何文本(没有惊喜).但是,写入内置值也会更新datalist值,反之亦然.
  • 该datalist值具有优先权,并将覆盖视图模型init上的内置值.之后他们保持同步.
  • options 应该是一个数组(普通的旧的或可观察的)对象 - 本例中的公司).
  • optionsText并且optionsValue是应该映射到选项属性的字符串.
  • 您不必使用optionsValue- 在这种情况下,将存储整个对象(单个公司)value.我宁愿只存储ID.
  • 目前,该设置对该change事件作出反应.这意味着在您离开输入字段之前,您的视图模型不会更新.
  • 在Chrome 32,YMMV上测试.正如我所说,欢迎提出意见和更正.

这是一个显示这个的小提琴:http://jsfiddle.net/GJ4h4/3/

  • 好的解决方案 我做了一些小改动:http://jsfiddle.net/GJ4h4/4/不再需要list属性,现在有一个选项可以在文本无效时清除它. (2认同)