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?
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 .
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.
Determining if a property is a computed observable Knockout provides a utility function, ko. isComputed to help with this situation.
Computed Observable is a function which is dependent on one or more Observables and automatically updates whenever its underlying Observables (dependencies) change.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With