有一个不一定是游戏破坏的问题。我有一个简单的排序表和2个过滤器。一个由数组填充的过滤器(活动,非活动,全部显示)和一个基于搜索条件的过滤器。
代码有效。但是,当我有开发人员工具时,我收到以下错误:
除非指定'write'选项,否则无法将值写入ko.computed。如果您想读取当前值,请不要传递任何参数。
我的代码在下面,我设置了一个JS小提琴,但我无法让它工作,所以我不确定它是否有用 - Fiddle
var sgsoip = window.sgsoip || {};
sgsoip.FunctionalArea = function (FunctionalAreaID, FunctionalAreaName, FunctionalAreaActive) {
'use strict';
this.FunctionalAreaID = ko.observable(FunctionalAreaID);
this.FunctionalAreaName = ko.observable(FunctionalAreaName);//.extend({ required: "Functional Area Name is required" });
this.FunctionalAreaActive = ko.observable(FunctionalAreaActive);//.extend({ required: "Active is required" });
//this.HasError = ko.pureComputed(function () {
// return this.FunctionalAreaActive.hasError() || this.FunctionalAreaName.hasError();
//}, this);
};
var sgsoip = window.sgsoip || {};
sgsoip.FunctionalAreaViewModel = function (ko) {
var self = this;
self.functionalAreas = ko.observableArray([]);
self.search = ko.observable('');
self.headers = [
{ title: '', sortPropertyName: '', asc: true, active: false },
{ title: 'Functional Area Name', sortPropertyName: 'FunctionalAreaName', asc: true, active: true },
{ title: 'Active', sortPropertyName: 'FunctionalAreaActive', asc: true, active: false }
];
self.filters = [
{ title: "Show All", filter: null },
{ title: "Active", filter: function (item) { return item.FunctionalAreaActive() === true; } },
{ title: "Inactive", filter: function (item) { return item.FunctionalAreaActive() === false; } }
];
self.activeFilter = ko.observable(self.filters[0].filter);
self.activeSort = ko.observable(function () { return 1; }); //set the default sort
self.setActiveFilter = function (model, event) {
self.activeFilter(model.filter);
}
self.sort = function (header, event) {
//if this header was just clicked a second time
if (header.active) {
header.asc = !header.asc; //toggle the direction of the sort
}
//make sure all other headers are set to inactive
ko.utils.arrayForEach(self.headers, function (item) { item.active = false; });
//the header that was just clicked is now active
header.active = true;//our now-active header
var prop = header.sortPropertyName;
var ascSort = function (a, b) { return a[prop]() < b[prop]() ? -1 : a[prop]() > b[prop]() ? 1 : a[prop]() == b[prop]() ? 0 : 0; };
var descSort = function (a, b) { return a[prop]() > b[prop]() ? -1 : a[prop]() < b[prop]() ? 1 : a[prop]() == b[prop]() ? 0 : 0; };
var sortFunc = header.asc ? ascSort : descSort;
//store the new active sort function
self.activeSort(sortFunc);
};
self.filteredItems = ko.computed(function () {
var result;
if (self.activeFilter()) {
result = ko.utils.arrayFilter(self.functionalAreas(), self.activeFilter());
} else {
result = self.functionalAreas();
}
if (self.search()) {
return (ko.utils.arrayFilter(result, function (item) {
return item.FunctionalAreaName().toLowerCase().indexOf(self.search().toLowerCase()) !== -1;
})).sort(self.activeSort());
} else {
return result.sort(self.activeSort());
}
});
self.removeFunctionalArea = function (FunctionalArea) {
var con = confirm("Are you sure you want to delete this record?");
if (con) {
$.post(
'/FunctionalAreas/Deactivate',
AddAntiForgeryToken({ id: FunctionalArea.FunctionalAreaID }))
.done(function () {
self.FunctionalAreas.remove(FunctionalArea)
//var parentRow = dataLink.parents("tr:first");
//parentRow.fadeOut('fast', function () {
// parentRow.remove();
//});
}).fail(function (data) {
alert("error");
});
return false;
}
}
function _init() {
//test code
var data =[{ FunctionalAreaID: 1, FunctionalAreaName: 'Test', FunctionalAreaActive: true },
{ FunctionalAreaID: 2, FunctionalAreaName: 'atest', FunctionalAreaActive: true },
{ FunctionalAreaID: 3, FunctionalAreaName: 'ZTest', FunctionalAreaActive: false }];
//real code
//db.getFunctionalAreas(function (data) {
var a = [];
ko.utils.arrayForEach(data || [], function (item) {
a.push(new sgsoip.FunctionalArea(item.FunctionalAreaID, item.FunctionalAreaName, item.FunctionalAreaActive));
});
self.functionalAreas(a);
// });
}
_init();
return {
sort: sort,
filteredItems: filteredItems,
setActiveFilter: setActiveFilter,
removeFunctionalArea: removeFunctionalArea
}
}(ko);
ko.applyBindings(sgsoip.FunctionalAreaViewModel);
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div class="container">
<div class="row">
<div class="col-sm-2 col-md-1">
<label for="searchString">Search:</label>
</div>
<div class="col-sm-3">
<input name="searchString" class="form-control" id="searchString" type="text" value="" data-bind="value: search, valueUpdate: 'afterkeydown', event: { keyup: filteredItems } ">
</div>
<div class="col-sm-2 col-md-1">
<label for="Filter:">Filter:</label>
</div>
<div class="col-sm-3">
<div class="btn-group" data-bind="foreach: filters">
<button class="btn btn-default" data-bind="click: setActiveFilter, text: title">Show All</button>
</div>
</div>
</div>
<div class="row extraTopMargin">
<div class="col-sm-12">
<table class="table table-striped" id="gridoutput">
<thead>
<tr data-bind="foreach: headers">
<th><a href="#" data-bind="click: sort, text: title"></a></th>
</tr>
</thead>
<tbody data-bind="foreach: filteredItems">
<tr>
<td><a href="javascript:void(0);" data-bind="click: removeFunctionalArea" title="Delete"><i class="glyphicon glyphicon-trash"></i></a></td>
<td data-bind="text: FunctionalAreaName"></td>
<td data-bind="text: FunctionalAreaActive"></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
如果您输入“z”,您会看到它可以正常工作,但是在打开开发人员工具时出现错误。如果我从计算中删除搜索条件的代码,只返回result.sort(self.activeSort());然后没有错误发生。我正在做的是进一步细化计算中的结果数组,我不确定是否违反了计算机的工作原理,但也许我是。
答案 0 :(得分:1)
您可以像这样绑定搜索输入
<input name="searchString" data-bind="
value: search,
valueUpdate: 'afterkeydown',
event: {
keyup: filteredItems
}
">
这意味着每次keyup事件发生时knockout都会调用filteredItems
。 filteredItems
定义为:
self.filteredItems = ko.computed(function () { /* ... */ })
即。只读计算。如果你用任何参数调用它,knockout会抱怨它不能写入只读的计算器。所以不要这样做。
<input name="searchString" data-bind="textInput: search">
目前还不清楚这个事件绑定应该达到什么目的。
另见:http://knockoutjs.com/documentation/textinput-binding.html
答案 1 :(得分:0)
你总是可以制作一个可写的计算可观察量:
this.fullName = ko.pureComputed({
read: function () {
return this.firstName() + " " + this.lastName();
},
write: function (value) {
var lastSpacePos = value.lastIndexOf(" ");
if (lastSpacePos > 0) { // Ignore values with no space character
this.firstName(value.substring(0, lastSpacePos)); // Update "firstName"
this.lastName(value.substring(lastSpacePos + 1)); // Update "lastName"
}
},
owner: this
});
来自:http://knockoutjs.com/documentation/computed-writable.html