Knockout JS Error: Cannot write a value to a ko.computed unless you specify a 'write' option

Cliff Chambers

Having an issue that isn't necessarily game breaking. I have a simple table with sort, and 2 filters. One filter populated by array (active, inactive, show all) and one based on search criteria.

The code works. But when I have developer tools up I get the following error:

Cannot write a value to a ko.computed unless you specify a 'write' option. If you wish to read the current value, don't pass any parameters.

My code is below, and I set up a JS Fiddle but I can't get it work, so 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 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>

If you type "z" you'll see that it works, but I get an error with developer tools open. If I remove the code for the search criteria from the computed, and just return result.sort(self.activeSort()); then no error occurs. All I'm doing is further refining the result array inside the computed, I am not sure that violates how a computed works, but perhaps I am.

Tomalak

You bind your search input like this

<input name="searchString" data-bind="
    value: search, 
    valueUpdate: 'afterkeydown', 
    event: { 
        keyup: filteredItems
    }
"> 

which means knockout will call filteredItems every time the keyup event happens. filteredItems is defined as:

self.filteredItems = ko.computed(function () { /* ... */ })

i.e. a read-only computed. If you call that with any argument, knockout will complain that it can't write to a read-only computed. So don't do that.

<input name="searchString" data-bind="textInput: search"> 

It's unclear what this event binding was supposed to achieve anyway.

Also see: http://knockoutjs.com/documentation/textinput-binding.html

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

Cannot write a value to a ko.computed unless you specify a 'write' option

From Dev

Error: Cannot write a value to a ko.computed unless you specify a 'write' option. If you wish to read the current value, don't pass any parameters

From Dev

Knockout Computed - write a new value

From Dev

knockout.js observableArray computed value

From Dev

Knockout - ko.computed with ko.isObservable and peek()

From Dev

Knockout - Difference between ko.computed and ko.observable.subscribe

From Dev

knockout foreach computed value

From Dev

knockout foreach computed value

From Dev

Put computed value inside progress bar Knockout js

From Dev

Can you write pure JavaScript expressions in Kendo MVVM views (as with Knockout)?

From Dev

ko.computed field for data-value

From Dev

Knockout Js computed not working in a model

From Dev

Knockout js Computed not being fired

From Dev

Knockout js Computed not being fired

From Dev

Error 24 : Write error : cannot write compressed block

From Dev

knockout: ko observable without a default value

From Dev

Knockout.js ko.dataFor

From Dev

Knockout JS - Invalid State Error using ko.toJSON and google maps

From Dev

knockout js selected option

From Dev

Write computed setter as a public function

From Dev

Knockout update computed value after blur

From Dev

should you use fread/fwrite or read/write system calls when you want to specify the buffer size explicitly?

From Dev

should you use fread/fwrite or read/write system calls when you want to specify the buffer size explicitly?

From Dev

Second computed function causes error in Knockout code

From Dev

Knockout js computed running balance infinite loops

From Dev

Knockout.js: Subscribe or computed observable?

From Dev

Knockout.js: computed observable not updating as expected

From Dev

Difference between subscribe and computed in knockout js

From Dev

Computed Observables with Revealing Prototype Pattern in Knockout JS

Related Related

  1. 1

    Cannot write a value to a ko.computed unless you specify a 'write' option

  2. 2

    Error: Cannot write a value to a ko.computed unless you specify a 'write' option. If you wish to read the current value, don't pass any parameters

  3. 3

    Knockout Computed - write a new value

  4. 4

    knockout.js observableArray computed value

  5. 5

    Knockout - ko.computed with ko.isObservable and peek()

  6. 6

    Knockout - Difference between ko.computed and ko.observable.subscribe

  7. 7

    knockout foreach computed value

  8. 8

    knockout foreach computed value

  9. 9

    Put computed value inside progress bar Knockout js

  10. 10

    Can you write pure JavaScript expressions in Kendo MVVM views (as with Knockout)?

  11. 11

    ko.computed field for data-value

  12. 12

    Knockout Js computed not working in a model

  13. 13

    Knockout js Computed not being fired

  14. 14

    Knockout js Computed not being fired

  15. 15

    Error 24 : Write error : cannot write compressed block

  16. 16

    knockout: ko observable without a default value

  17. 17

    Knockout.js ko.dataFor

  18. 18

    Knockout JS - Invalid State Error using ko.toJSON and google maps

  19. 19

    knockout js selected option

  20. 20

    Write computed setter as a public function

  21. 21

    Knockout update computed value after blur

  22. 22

    should you use fread/fwrite or read/write system calls when you want to specify the buffer size explicitly?

  23. 23

    should you use fread/fwrite or read/write system calls when you want to specify the buffer size explicitly?

  24. 24

    Second computed function causes error in Knockout code

  25. 25

    Knockout js computed running balance infinite loops

  26. 26

    Knockout.js: Subscribe or computed observable?

  27. 27

    Knockout.js: computed observable not updating as expected

  28. 28

    Difference between subscribe and computed in knockout js

  29. 29

    Computed Observables with Revealing Prototype Pattern in Knockout JS

HotTag

Archive