knockout.js - Knockout JS Error: Cannot write a value to a ko.computed unless you specify a 'write' option -
having issue isn't game breaking. have simple table sort, , 2 filters. 1 filter populated array (active, inactive, show all) , 1 based on search criteria.
the code works. when have developer tools following error:
cannot write value ko.computed unless specify 'write' option. if wish read current value, don't pass parameters.
my code below, , set js fiddle can't work, i'm not sure it's helpful - 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 required" }); this.functionalareaactive = ko.observable(functionalareaactive);//.extend({ required: "active 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 default sort self.setactivefilter = function (model, event) { self.activefilter(model.filter); } self.sort = function (header, event) { //if header clicked second time if (header.active) { header.asc = !header.asc; //toggle direction of sort } //make sure other headers set inactive ko.utils.arrayforeach(self.headers, function (item) { item.active = false; }); //the header clicked 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 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 sure want delete 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 = []; 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> if type "z" you'll see works, error developer tools open. if remove code search criteria computed, , return result.sort(self.activesort()); no error occurs. i'm doing further refining result array inside computed, not sure violates how computed works, perhaps am.
you bind search input this
<input name="searchstring" data-bind=" value: search, valueupdate: 'afterkeydown', event: { keyup: filtereditems } "> which means knockout call filtereditems every time keyup event happens. filtereditems defined as:
self.filtereditems = ko.computed(function () { /* ... */ }) i.e. read-only computed. if call argument, knockout complain can't write read-only computed. don't that.
<input name="searchstring" data-bind="textinput: search"> it's unclear event binding supposed achieve anyway.
also see: http://knockoutjs.com/documentation/textinput-binding.html
Comments
Post a Comment