0
votes

I have a Knockout view model which contains a computed observable that simply filters some raw data based on the contents of a textual input. This computed observable is then bound to a table to display the information.

Each time the computed observable is calculated, I need to have a function run which updates some event listeners on the table rows (I have this function already).

However, I have been unable to fathom how to get it to run after the computed observable has updated. Placing a call to the function within the observable function does it before the new value is returned so actions it with legacy data. I have also considered extender syntax, but believe this to be an inappropriate solution.

If anyone has a solution or any pointers, I would greatly appreciate it.

UPDATE WITH CODE:

var viewModel = function(data) {
    var self = this;
    self.search = ko.observable('');
    self.rawData = ko.observableArray(data);
    self.filterData = ko.computed(function() {
        return self.rawData().filter(function(item) {
            var filter = self.search().toLowerCase();
            return item.employeeNumber.toString().includes(filter) || item.name.toLowerCase().includes(filter) || filter == "";
        });
    });
};

Async function creates a new view model with the returned data and applies the bindings.

function reevaluateHandlers() {
    // Code that should run every time the computed observable is calculated (filterData)
}
1
can you post your code ? - C.Fasolin
@C.Fasolin I have added some code in though I'm not sure of how much value it adds. - dbr

1 Answers

1
votes

Mulitple Ways to do it:

  1. Have another computed function after this function, this would then fire after your first computed function ie.

    self.filterData = ko.computed(function() {
        return self.rawData().filter(function(item) {
            var filter = self.search().toLowerCase();
            return item.employeeNumber.toString().includes(filter) || item.name.toLowerCase().includes(filter) || filter == "";
        });
    });
    
    self.reevaluateHandlers = ko.computed(function() {
        var rawData = self.rawData();
        var filter = self.search();
        reevaluateHandlers();
    });
    
  2. Simple Timeout Function, the reevaluateHandlers function will fire after data is returned

    self.filterData = ko.computed(function() {
        var rawData = self.rawData();
        var filter = self.search().toLowerCase();
        var filteredData = rawData.filter(function(item) {
            return item.employeeNumber.toString().includes(filter) || item.name.toLowerCase().includes(filter) || filter == "";
        });
    
        setTimeout(function() {
            reevaluateHandlers();
        }, 100);
    
        return filteredData;
    });
    

I think the first solution is more efficient, although i would optimise the filterdata code with:

var filter = self.search().toLowerCase();

Its minimal but it will make a difference, especially with array size increasing. Also look at linqjs and knockouts pauseablecomputed, as then you are in control of when the computeds fire .