Search code examples
dictionaryknockout.jsknockout-mapping-plugin

Can't load dictionary using knockout mapping plugin


I found the solution how to use the observable array as dictionary on http://jsfiddle.net/karlhorky/D4D3f/

ko.observableArray.fn.indexBy = function (keyName) {
    var index = ko.computed(function () {
        var list = this() || [];
        var keys = {}; 
        ko.utils.arrayForEach(list, function (v) {
            if (keyName) {          
                keys[v[keyName]] = v;   
            } else {
                keys[v] = v;
            }
        });
        return keys;
    }, this);

    this.findByKey = function(key) {
        return index()[key];  
    };

    return this;
};

I'd like to load data to dictionary using mapping plugin

this.Load = function () {
    //this.items.
    var mapping = {
        'copy': ["Qid"]
    };
    ko.mapping.fromJS(data, mapping, this.items);
    count = 0;
};

but can't search by key data loaded using mapping plugin

demo: http://jsfiddle.net/RqSDv/


Solution

  • The mapping plugin turns regular properties into observable properties.

    So in your indexBy you need to handle the case when your keyName refers to a ko.observable.

    When you get the key property value with v[keyName] you need to use ko.utils.unwrapObservable (or ko.unwrap if you using a newer version of KO) to make sure to correctly unwrap your observable property:

    ko.observableArray.fn.indexBy = function (keyName) {
        var index = ko.computed(function () {
            var list = this() || [];
            var keys = {};
            ko.utils.arrayForEach(list, function (v) {
                if (keyName) {
                    keys[ko.utils.unwrapObservable(v[keyName])] = v;
                } else {
                    keys[v] = v;
                }
            });
            return keys;
        }, this);
    
        this.findByKey = function (key) {
            return index()[key];
        };
    
        return this;
    };
    

    Demo JSFiddle.