Knockout.JS: My console says "Uncaught TypeError: Cannot read property 'toLowerCase' of undefined" when i try to search something
Knockout.JS: My console says "Uncaught TypeError: Cannot read property 'toLowerCase' of undefined" when i try to search something
我想用 knockout JS 创建一个搜索和下拉过滤器。我的下拉过滤器工作得很好,但是当我尝试搜索位置时,我的控制台给我这个错误:
Uncaught TypeError: Cannot read property 'toLowerCase' of undefined
ko.utils.stringStartsWith = function(string, startsWith) {
string = string || " ";
if (startsWith.length > string.length) return false;
return string.substring(0, startsWith.length) == startsWith;
};
var Record = function(dropType, dropName, dropAddress, homeTown) {
this.dropType = dropType;
this.dropName = dropName;
this.dropAddress = dropAddress;
this.homeTown = homeTown;
};
var ViewModel = function(records, homeTowns) {
var self = this;
self.homeTowns = ko.observableArray(homeTowns);
self.records = ko.observableArray(
ko.utils.arrayMap(records, function(r) {
return new Record(r.dropType, r.dropName, r.dropAddress, r.homeTown);
}));
// search filter
self.dropTypeSearch = ko.observable('');
self.dropNameSearch = ko.observable('');
self.townSearch = ko.observable('');
self.filteredRecords = ko.computed(function() {
return ko.utils.arrayFilter(self.records(), function(x) {
return (self.dropNameSearch().length == 0 || ko.utils.stringStartsWith(x.dropName.toLowerCase(), self.dropNameSearch().toLowerCase())) && (self.townSearch().length == 0 || x.homeTown == self.townSearch())
});
});
};
var homeTowns = ["Search Location", "Kalk Bay", "Simon's Town", "Muizenberg", "Claremont"];
var data = [{}, {
id: 1,
dropType: "Shelter",
dropName: "The Haven, Kalk Bay",
dropAddress: "139 Main Road, Kalk Bay",
homeTown: "Kalk Bay",
}, {
id: 2,
dropType: "Shelter",
dropName: "Happy Valley Simon's Town",
dropAddress: "Palace Hill Road, Simon's Town",
homeTown: "Simon's Town",
}, {
id: 3,
dropType: "Meals",
dropName: "Living Grace Community Centre",
dropAddress: "171 Main Road, Muizenberg",
homeTown: "Muizenberg",
}, {
id: 4,
dropType: "Shelter",
dropName: "The Haven, Claremont",
dropAddress: "PO Box 23999, Claremont, 5 Fir Street",
homeTown: "Claremont",
}, ];
ko.applyBindings(new ViewModel(data, homeTowns));
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/2.3.0/knockout-min.js"></script>
//search input Name: <input data-bind="value: dropNameSearch, valueUpdate: 'afterkeyup'" /> Location: <select data-bind="options: homeTowns, value: townSearch"></select> //drop-down filter
<div data-bind="foreach: filteredRecords" class="record">
<ul>
<li>
Type: <span data-bind="text: dropType"></span>
</li>
<li>
Name: <span data-bind="text: dropName"></span>
</li>
<li>
Address: <span data-bind="text: dropAddress"> </span>
</li>
<li>
Location: <span data-bind="text: homeTown"></span>
</li>
</ul>
</div>
我是 Knockout.js 的新手。 JS fiddle 或片段 运行 将不胜感激。
因为函数是window对象的一部分,而不是输入元素对象。因此,计算函数,您调用的函数是 window 对象的一部分。此对象将引用 window。使用 call 或 apply,您可以将 this 的引用更改为另一个对象。在这种情况下,您的输入字段。当你有机会时,研究 "call" 和 "apply"。它将帮助您更好地理解它。
您的数据中有一个空对象,因此这将导致 Record 实例的属性未定义。消除错误的一种方法是将默认值添加到 Record 函数。
var Record = function(dropType, dropName, dropAddress, homeTown) {
this.dropType = dropType || "";
this.dropName = dropName || "";
this.dropAddress = dropAddress || "";
this.homeTown = homeTown || "";
};
这将确保所有属性都是字符串类型并修复错误。
但是,filteredRecords
计算变量中的代码逻辑仍然存在一些错误。如果 dropNameSearch()
中有值且 townSearch()
值为 "Search Location"
,则结果仍为空,因为没有数据的 homeTown
值为 "Search Location"
。
要解决此问题,请遵循以下逻辑顺序:
- 如果
dropNameSearch
为空,townSearch
为"Search Location",则return[]
.
- 如果
dropNameSearch
中有值,则根据其值进行初始过滤。
- 如果
townSearch
的值不是"Search Location"
,则根据它的值进行二次过滤
这是一个示例 fiddle:https://jsfiddle.net/8z5Lmcau/
我想用 knockout JS 创建一个搜索和下拉过滤器。我的下拉过滤器工作得很好,但是当我尝试搜索位置时,我的控制台给我这个错误:
Uncaught TypeError: Cannot read property 'toLowerCase' of undefined
ko.utils.stringStartsWith = function(string, startsWith) {
string = string || " ";
if (startsWith.length > string.length) return false;
return string.substring(0, startsWith.length) == startsWith;
};
var Record = function(dropType, dropName, dropAddress, homeTown) {
this.dropType = dropType;
this.dropName = dropName;
this.dropAddress = dropAddress;
this.homeTown = homeTown;
};
var ViewModel = function(records, homeTowns) {
var self = this;
self.homeTowns = ko.observableArray(homeTowns);
self.records = ko.observableArray(
ko.utils.arrayMap(records, function(r) {
return new Record(r.dropType, r.dropName, r.dropAddress, r.homeTown);
}));
// search filter
self.dropTypeSearch = ko.observable('');
self.dropNameSearch = ko.observable('');
self.townSearch = ko.observable('');
self.filteredRecords = ko.computed(function() {
return ko.utils.arrayFilter(self.records(), function(x) {
return (self.dropNameSearch().length == 0 || ko.utils.stringStartsWith(x.dropName.toLowerCase(), self.dropNameSearch().toLowerCase())) && (self.townSearch().length == 0 || x.homeTown == self.townSearch())
});
});
};
var homeTowns = ["Search Location", "Kalk Bay", "Simon's Town", "Muizenberg", "Claremont"];
var data = [{}, {
id: 1,
dropType: "Shelter",
dropName: "The Haven, Kalk Bay",
dropAddress: "139 Main Road, Kalk Bay",
homeTown: "Kalk Bay",
}, {
id: 2,
dropType: "Shelter",
dropName: "Happy Valley Simon's Town",
dropAddress: "Palace Hill Road, Simon's Town",
homeTown: "Simon's Town",
}, {
id: 3,
dropType: "Meals",
dropName: "Living Grace Community Centre",
dropAddress: "171 Main Road, Muizenberg",
homeTown: "Muizenberg",
}, {
id: 4,
dropType: "Shelter",
dropName: "The Haven, Claremont",
dropAddress: "PO Box 23999, Claremont, 5 Fir Street",
homeTown: "Claremont",
}, ];
ko.applyBindings(new ViewModel(data, homeTowns));
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/2.3.0/knockout-min.js"></script>
//search input Name: <input data-bind="value: dropNameSearch, valueUpdate: 'afterkeyup'" /> Location: <select data-bind="options: homeTowns, value: townSearch"></select> //drop-down filter
<div data-bind="foreach: filteredRecords" class="record">
<ul>
<li>
Type: <span data-bind="text: dropType"></span>
</li>
<li>
Name: <span data-bind="text: dropName"></span>
</li>
<li>
Address: <span data-bind="text: dropAddress"> </span>
</li>
<li>
Location: <span data-bind="text: homeTown"></span>
</li>
</ul>
</div>
我是 Knockout.js 的新手。 JS fiddle 或片段 运行 将不胜感激。
因为函数是window对象的一部分,而不是输入元素对象。因此,计算函数,您调用的函数是 window 对象的一部分。此对象将引用 window。使用 call 或 apply,您可以将 this 的引用更改为另一个对象。在这种情况下,您的输入字段。当你有机会时,研究 "call" 和 "apply"。它将帮助您更好地理解它。
您的数据中有一个空对象,因此这将导致 Record 实例的属性未定义。消除错误的一种方法是将默认值添加到 Record 函数。
var Record = function(dropType, dropName, dropAddress, homeTown) {
this.dropType = dropType || "";
this.dropName = dropName || "";
this.dropAddress = dropAddress || "";
this.homeTown = homeTown || "";
};
这将确保所有属性都是字符串类型并修复错误。
但是,filteredRecords
计算变量中的代码逻辑仍然存在一些错误。如果 dropNameSearch()
中有值且 townSearch()
值为 "Search Location"
,则结果仍为空,因为没有数据的 homeTown
值为 "Search Location"
。
要解决此问题,请遵循以下逻辑顺序:
- 如果
dropNameSearch
为空,townSearch
为"Search Location",则return[]
. - 如果
dropNameSearch
中有值,则根据其值进行初始过滤。 - 如果
townSearch
的值不是"Search Location"
,则根据它的值进行二次过滤
这是一个示例 fiddle:https://jsfiddle.net/8z5Lmcau/