我无法弄清楚这个错误在我的小提琴中意味着什么。将光标放在最后一行的最后一个输入中并选中。它应该添加一个新行。但是我的代码中出现了错误。我得到的错误是TypeError: itemNo(...) is undefined
。这是我的小提琴:https://jsfiddle.net/tLfezuu1/1/
HTML:
<table class="table table-bordered table-striped" id="brochureItems">
<thead>
<tr>
<th>
Item No
</th>
<th>
Bro Code
</th>
<th width="36%">
Desc
</th>
<th width="15%">
Retail
</th>
<th>
Prize Cnt
</th>
<th>
Order
</th>
<th>
Remove
</th>
</tr>
</thead>
<tbody data-bind="foreach: items">
<tr>
<td>
<div data-bind="if: (itemNo().length < 1)"><input data-bind="value: itemNo, hasFocus: invalidItem(), selected: invalidItem(), event: { blur: $parent.checkItemNo }, attr: { name: 'brochureitems[' + $index() + '].itemNo', id: 'brochureItems_' + $index() + '__itemNo' }, validationOptions: { errorElementClass: 'input-validation-error' }" class="form-control item-id" /></div>
<div data-bind="if: (itemNo().length > 0)"><input data-bind="value: itemNo, attr: { name: 'brochureitems[' + $index() + '].itemNo', id: 'brochureItems_' + $index() + '__itemNo' }, validationOptions: { errorElementClass: 'input-validation-error' }" class="form-control item-ID" readonly="readonly" tabindex="-1" /></div>
</td>
<td>
<div data-bind="if: (brocCode.length < 1)">
<input data-bind="value: brocCode, insertPress: $index, attr: { name: 'brochureitems[' + $index() + '].brocCode', id: 'brochureItems_' + $index() + '__brocCode' }, validationOptions: { errorElementClass: 'input-validation-error' }" class="form-control" />
</div>
<div data-bind="if: (brocCode.length > 0)">
<input data-bind="value: brocCode, insertPress: $index, attr: { name: 'brochureitems[' + $index() + '].brocCode', id: 'brochureItems_' + $index() + '__brocCode' }, validationOptions: { errorElementClass: 'input-validation-error' }" class="form-control" readonly="readonly" tabindex="-1" />
</div>
</td>
<td class="item-desc">
<input data-bind="value: itemDesc, attr: { name: 'brochureitems[' + $index() + '].itemDesc', id: 'brochureItems_' + $index() + '__itemDesc' }, validationOptions: { errorElementClass: 'input-validation-error' }" class="form-control" readonly="readonly" tabindex="-1" />
</td>
<td class="item-retail">
<div class="input-group">
<div class="input-group-addon">$</div>
<div data-bind="if: ($index() === ($parent.items().length - 1))"><input data-bind="value: retail, valueUpdate: 'afterkeydown', attr: { name: 'brochureitems[' + $index() + '].retail', id: 'brochureItems_' + $index() + '__retail' }, validationOptions: { errorElementClass: 'input-validation-error' }, style: { backgroundColor: retail == 0 ? '#FFFCCE' : '#ffffff'}" class="form-control" /></div>
<div data-bind="if: ($index() < ($parent.items().length - 1))"><input data-bind="value: retail, valueUpdate: 'afterkeydown', money: retail, attr: { name: 'brochureitems[' + $index() + '].retail', id: 'brochureItems_' + $index() + '__retail' }, validationOptions: { errorElementClass: 'input-validation-error' }, style: { backgroundColor: retail == 0 ? '#FFFCCE' : '#ffffff'}" class="form-control" readonly="readonly" tabindex="-1" /></div>
</div>
</td>
<td>
<div><input data-bind="value: prizeNum, valueUpdate: 'afterkeydown', attr: { name: 'brochureitems[' + $index() + '].prizeNum', id: 'brochureItems_' + $index() + '__prizeNum' }, validationOptions: { errorElementClass: 'input-validation-error' }, style: { backgroundColor: prizeNum == 0 ? '#FFFCCE' : '#ffffff'}" class="form-control" /></div>
</td>
<td>
<div data-bind="if: ($index() === ($parent.items().length - 1))"><input data-bind="value: itemOrder, valueUpdate: 'afterkeydown', enterPress: 'addRow', attr: { name: 'brochureitems[' + $index() + '].itemOrder', id: 'brochureItems_' + $index() + '__itemOrder' }, validationOptions: { errorElementClass: 'input-validation-error' }, style: { backgroundColor: itemOrder == 0 ? '#FFFCCE' : '#ffffff'}" class="form-control" /></div>
<div data-bind="if: ($index() < ($parent.items().length - 1))"><input data-bind="value: itemOrder, valueUpdate: 'afterkeydown', attr: { name: 'brochureitems[' + $index() + '].itemOrder', id: 'brochureItems_' + $index() + '__itemOrder' }, validationOptions: { errorElementClass: 'input-validation-error' }, style: { backgroundColor: itemOrder == 0 ? '#FFFCCE' : '#ffffff'}" class="form-control" /></div>
</td>
<td class="remove"><span class="glyphicon glyphicon-remove removeRow" data-bind="click: $parent.removeItem"></span></td>
</tr>
</tbody>
</table>
淘汰赛:
ko.validation.rules.pattern.message = 'Invalid.';
ko.validation.init({
registerExtenders: true,
messagesOnModified: true,
insertMessages: true,
parseInputAttributes: true,
messageTemplate: null,
decorateInputElement: true,
}, true);
(function(){
var toMoney = function(num){
if(num != null && num != "") {
num = parseFloat(num);
return (num.toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, '$1,') );
} else {
return "";
}
};
var handler = function(element, valueAccessor, allBindings){
var $el = $(element);
var method;
// Gives us the real value if it is a computed observable or not
var valueUnwrapped = ko.unwrap( valueAccessor() );
if($el.is(':input')){
method = 'val';
} else {
method = 'text';
}
return $el[method]( toMoney( valueUnwrapped ) );
};
ko.bindingHandlers.money = {
update: handler
};
})();
var itemModel = function (data) {
var self = this;
self.invalidItem = ko.observable(true);
self.itemNo = ko.observable(data ? data.itemNo : undefined).extend( {
required: {
params: true,
message: "Item no. required."
}
});
self.brocCode = ko.observable(data ? data.brocCode : undefined).extend( {
required: {
params: true,
message: "Bro code required."
}
});
self.itemDesc = ko.observable(data ? data.itemDesc : undefined).extend( {
required: {
params: true,
message: "Item desc required."
}
});
self.retail = ko.observable(data ? data.retail : undefined).extend( {
required: {
params: true,
message: "Retail required."
}
})
.extend({numeric: 2});
self.prizeNum = ko.observable(data ? data.prizeNum : undefined).extend( {
required: {
params: true,
message: "Prize num required."
}
});
self.itemOrder = ko.observable(data ? data.itemOrder : undefined).extend( {
required: {
params: true,
message: "Item order required."
}
});
}
var itemsModel = function(items) {
var self = this;
self.items = ko.mapping.fromJSON(items);
//self.invalidItem = ko.observable(true);
self.checkItemNo = function(data) {
console.log("lost focus - " + self.invalidItem());
var itemNo = $.trim(data.itemNo());
if (itemNo != "") {
var item = "";
$.each(window.listOfItems, function(i, v) {
if (v.No.search(itemNo) != -1) {
item = v.Description;
return;
}
});
if(item != "") {
var match = ko.utils.arrayFirst(self.items(), function(newItem) {
return itemNo === newItem.itemNo;
});
console.log("match: " + match);
if (!match) {
data.itemDesc(item);
} else { // item already entered
//setTimeout(function() { self.items.invalidItem(true); }, 1);
data.itemDesc("");
slideDownMsg("Item already entered.");
slideUpMsg(3000);
}
} else { // invalid item #
console.log(data);
data.invalidItem(true);
//setTimeout(function() { data.invalidItem(true); }, 1);
data.itemDesc("");
slideDownMsg("Invalid item number.");
slideUpMsg(3000);
}
}
}
self.submit = function() {
//self.showErrors(true);
if (viewModel.errors().length === 0) {
console.log('Thank you.');
$("#brochureForm").submit();
}
else {
console.log('Please check your submission.');
viewModel.errors.showAllMessages();
$(".input-validation-error").first().focus();
}
}
self.addLine = function() {
var iModel = new itemModel();
iModel.invalidItem(true);
//self.invalidItem(true);
console.log("adding new line; it is: " + iModel.invalidItem());
self.items.push( iModel );
//setTimeout(function() { self.invalidItem(true); }, 1);
};
self.insertLine = function(index) {
self.items.splice(index, 0, new itemModel() );
};
self.removeItem = function(item) {
self.items.remove(item);
};
self.errors = ko.validation.group(self.items, { deep: true, live: true });
self.validate = function() {
self.errors.showAllMessages();
}
};
ko.bindingHandlers.enterPress = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var allBindings = allBindingsAccessor();
element.addEventListener('keydown', function (event) {
var keyCode = (event.which ? event.which : event.keyCode);
if (keyCode === 13 || (!event.shiftKey && keyCode === 9)) {
event.preventDefault();
//bindingContext.$root.invalidItem(false);
bindingContext.$root.addLine();
return false;
}
return true;
});
}
};
ko.bindingHandlers.insertPress = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var allBindings = allBindingsAccessor();
element.addEventListener('keydown', function (event) {
var keyCode = (event.which ? event.which : event.keyCode);
if (keyCode === 45) {
event.preventDefault();
bindingContext.$root.insertLine(ko.unwrap(valueAccessor()));
return false;
}
return true;
});
}
};
ko.bindingHandlers.selected = {
update: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var selected = ko.utils.unwrapObservable(valueAccessor());
if (selected) element.select();
}
};
function GetItems() {
var itemsJSON = '[{"brochureId":1,"itemNo":"1000","brocCode":"1000","itemDesc":"Bicycle","retail":13.5, "prizeNum":1, "itemOrder":1},{"brochureId":1,"itemNo":"1100","brocCode":"1100","itemDesc":"Front Wheel","retail":35, "prizeNum":2, "itemOrder":2},{"brochureId":1,"itemNo":"1120","brocCode":"1120","itemDesc":"Spokes","retail":12.5, "prizeNum":3, "itemOrder":3},{"brochureId":1,"itemNo":"1150","brocCode":"1150","itemDesc":"Front Hub","retail":5, "prizeNum":4, "itemOrder":4},{"brochureId":1,"itemNo":"1151","brocCode":"1151","itemDesc":"Axle Front Wheel","retail":14, "prizeNum":5, "itemOrder":5},{"brochureId":1,"itemNo":"120","brocCode":"120","itemDesc":"Loudspeaker, Black, 120W","retail":12.5, "prizeNum":6, "itemOrder":6},{"brochureId":1,"itemNo":"125","brocCode":"125","itemDesc":"Socket Back","retail":10, "prizeNum":7, "itemOrder":7}]';
var viewModel = new itemsModel(itemsJSON);
ko.applyBindings(viewModel, $("#brochureItems")[0]);
}
$(document).ready(function () {
GetItems();
});
答案 0 :(得分:2)
它说itemNo
未定义,因为如果没有传入数据,则将itemNo
设置为undefined:
self.itemNo = ko.observable(data ? data.itemNo : undefined)...
你可以做到
self.itemNo = ko.observable(data ? data.itemNo : '').extend({
required: {
params: true,
message: "Item no. required."
}
});