Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get a ko.computed to work on observables inside an object

Tags:

knockout.js

I have a fairly simple view model to hold an array of data and take a string which I want to use to filter the data.

I have some very simple mark-up to render it like this:

<section class="task-list">
    <ul data-bind="foreach:filteredRecords">
        <li>
            <label>Task name:</label>
            <span data-bind="text:TaskName"></span>              
        </li>
    </ul>
</section>

and I've set up the model as follows;

var viewModel = {

    searchText : ko.observable(''),
    taskData : ko.observableArray([]),

    searchData : function () {

        // use ko.utils.arrayFilter to limit records by searchText()
        return this.taskData();
    },

    filterRecords: ko.computed(this.searchData, this).extend({ throttle: 500 }),
};

ko.applyBindings(viewModel, $('.task-list')[0]); 

What I get is

Uncaught Error: Pass a function that returns the value of the ko.computed 

moving the function back inside the ko:computed like this:

 filteredRecords: ko.computed(function () {
        return this.taskData();
    },this).extend({ throttle: 500 })

just gives me this error insread:

Uncaught TypeError: Object [object global] has no method 'taskData' 

So tried to define another property to use instead:

var viewModel = {

    _self : this,

    searchText : ko.observable(''),
    taskData : ko.observableArray([]),

    filteredRecords: ko.computed(function () {
        return this.taskData();
    },this).extend({ throttle: 500 })
};

but this now gives the error

Uncaught ReferenceError: _self is not defined 

finally I tried doing this:

var viewModel = {

    searchText : ko.observable(''),
    taskData : ko.observableArray([]),

    filteredRecords: ko.computed(function() {
        var me = this;
        return function () {
            return me.taskData();
        }
    },this).extend({ throttle: 500 })
};

Now this, does not throw any of the previous errors but also does not yield any results in the HTML either...

I've set up a Fiddle at

How do I correctly apply a ko.computed to an object so that I can use the observable and observableArray that I have inside the object?

like image 456
Code Uniquely Avatar asked Feb 04 '14 13:02

Code Uniquely


People also ask

How do you get the Knockout value from observable?

To read the observable's current value, just call the observable with no parameters. In this example, myViewModel. personName() will return 'Bob' , and myViewModel. personAge() will return 123 .

How do we activate a Knockout model?

Activating Knockout To activate Knockout, add the following line to a <script> block: ko. applyBindings(myViewModel); You can either put the script block at the bottom of the HTML document, or you can put it at the top and wrap the contents in a DOM-ready handler such as jQuery's $ function.

Which function is used to perform Knockout computation?

Determining if a property is a computed observable Knockout provides a utility function, ko. isComputed to help with this situation.

What is computed observable in knockout JS?

Computed Observable is a function which is dependent on one or more Observables and automatically updates whenever its underlying Observables (dependencies) change.


1 Answers

While you are defining an object literal, you are not able to reference any of the properties of it until after it is created. The value of this will not be your new object.

You can either use a constructor function like:

var ViewModel = function() {
   this.searchText = ko.observableArray();
   this.taskData = ko.observableArray([]);

   this.filteredRecords = ko.computed(function() {
        //filter logic here, can use `this` and reference searchText/taskData
    },this).extend({ throttle: 500 })
};

then, create a new instance of it like:

ko.applyBindings(new ViewModel(), $('.task-list')[0]); 

Otherwise, you could create your viewModel first before adding the computed. Then do:

viewModel.filteredRecords = ko.computed(function() {
  //filter logic here, can use `this` and reference searchText/taskData
}, viewModel);

This answer might help too: Difference between knockout View Models declared as object literals vs functions

like image 83
RP Niemeyer Avatar answered Sep 29 '22 02:09

RP Niemeyer