我的目标:使用 KnockoutJS 我有一组输入文本字段,用户可以在其中输入他们的产品名称,typeahead.js 将为每个文本框提供自动建议。可以动态添加或删除更多这些文本字段。
查看实时示例(JS Fiddle):http: //jsfiddle.net/justosophy/5Z9We/
问题是: Typeahead 适用于初始文本字段,但仅部分适用于动态字段。淘汰赛自定义绑定 allBindingsAccessor() 未定义,因此无法保存该值。
错误:
TypeError: string is not a function
HTML:
<div data-bind="foreach: products">
<div class="product">
<label>Enter Product Name:</label>
<input type="text" class="text-input product-search" data-bind="typeahead: productName, value: productName, productNameVal: productName, productIDVal: productID, valueUpdate: 'afterkeydown'" />
<a class="btn btn-danger" data-bind="click: $root.removeProduct" title="remove">remove</a>
</div>
</div>
<a class="btn btn-primary" data-bind="click: addProduct">Add another product</a>
JavaScript:
var my = {}, i;
// Create two initial entry boxes
my.initialData = [];
for (i = 2; i !== 0; i -= 1) {
my.initialData.push({ productName: "", productID: 0 });
}
// Knockout model
my.ProductsModel = function (products) {
var self = this;
self.products = ko.observableArray(ko.utils.arrayMap(products, function (product) {
return {
productName: ko.observable(product.productName),
productID: ko.observable(product.productID)
};
}));
self.addProduct = function () {
self.products.push({
productName: "",
productID: 0
});
};
self.removeProduct = function (product) {
self.products.remove(product);
};
};
// List of product options
my.productsList = [
{ value: 'alpha', productID: 1 },
{ value: 'apple', productID: 2 },
{ value: 'beta', productID: 3 },
{ value: 'bannana', productID: 4 },
{ value: 'gamma', productID: 5 },
{ value: 'grape', productID: 6 },
{ value: 'delta', productID: 7 },
{ value: 'dragonfruit',productID: 8 },
{ value: 'diamond',productID: 9 }
];
// Typeahead handler
ko.bindingHandlers.typeahead = {
init: function (element, valueAccessor, allBindingsAccessor) {
var $e = $(element),
productNameVal = allBindingsAccessor().productNameVal,
productIDVal = allBindingsAccessor().productIDVal;
var updateValues = function(datum) {
productNameVal(datum.value);
productIDVal(datum.productID);
};
$e.typeahead({
name: 'products',
local: my.productsList
}).on('typeahead:selected', function (el, datum) {
updateValues(datum);
}).on('typeahead:autocompleted', function (el, datum) {
updateValues(datum);
}).blur(function () {
var el, val, arrayCheck;
el = $(this);
val = el.val();
arrayCheck = ($.grep(my.productsList, function (n) { return n.value === val; }).length !== 0);
if (!arrayCheck) {
el.val('');
source('');
productIDVal(0);
}
});
}
};
// Apply bindings
$(document).ready(function () {
ko.applyBindings(new my.ProductsModel(my.initialData));
});