简体   繁体   中英

Knockout.js: computed observable not updating as expected

Edit: Added code for function populateDropdown and function isSystemCorrect (see bottom)

Edit 2 I have narrowed it down a bit and the problem seems to arise in the arrayFilter function in the computed observable. This returns an empty array, no matter what I try. I have checked that self.testsuites() looks ok right before filtering, but the filtering still fails.

I have a problem with my computed observable, filteredTestsuites.

As you can see from the screendump, the testsuites observable is populated correctly, but the computed observable remains empty. I have also tried choosing another option than "Payment" from the dropdown menu, to see if this will trigger the observable, it did not.

I would think the computed observable would be updated every time self.testsuites() or self.dropdownSelected() was changed, but it doesnt seem to trigger on neither of them.

What am I doing wrong here?

I simply want to make the computed observable filter the testsuites after the chosen dropdown option, every time either of them change.

来自控制台的屏幕转储

function ViewModel() {
    var self = this;

    // The item currently selected from a dropdown menu
    self.dropdownSelected = ko.observable("Payment");

    // This will contain all testsuites from all dropdown options
    self.testsuites = ko.mapping.fromJS('');

    // This will contain only testsuites from the chosen dropdown option
    self.filteredTestsuites = ko.computed(function () {
        return ko.utils.arrayFilter(self.testsuites(), function (testsuite) {
            return (isSystemCorrect(testsuite.System(), self.dropdownSelected()));
        });
    }, self);

    // Function for populating the testsuites observableArray
    self.cacheTestsuites = function (data) {
        self.testsuites(ko.mapping.fromJS(data));
    };


    self.populateDropdown = function(testsuiteArray) {

        for (var i = 0, len = testsuiteArray().length; i < len; ++i) {

            var firstNodeInSystem = testsuiteArray()[i].System().split("/")[0];

            var allreadyExists = ko.utils.arrayFirst(self.dropdownOptions(), function(option) {
                return (option.Name === firstNodeInSystem);
            });

            if (!allreadyExists) {
                self.dropdownOptions.push({ Name: firstNodeInSystem });
            }
        }
    };
}


$(document).ready(function () {

    $.getJSON("/api/TestSuites", function (data) {
        vm.cacheTestsuites(data);
        vm.populateDropdown(vm.testsuites());
        ko.applyBindings(vm);
    });
}

Function isSystemCorrect:

function isSystemCorrect(system, partialSystem) {

    // Check if partialSystem is contained within system. Must be at beginning of system and go
    // on to the end or until a "/" character.
    return ((system.indexOf(partialSystem) == 0) && (((system[partialSystem.length] == "/")) ||     (system[partialSystem.length] == null)));
}

As suggested in a comment - rewrite the cacheTestsuites method:

self.testsuites = ko.observableArray();
self.filteredTestsuites = ko.computed(function () {
    return ko.utils.arrayFilter(self.testsuites(), function (testsuite) {            
        return (isSystemCorrect(testsuite.System(), self.dropdownSelected()));
    });
});
self.cacheTestsuites = function (data) {
    var a = ko.mapping.fromJS(data);
    self.testsuites(a());
};

The only thing different here is the unwrapping of the observableArray from the mapping function.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM