ko.observableArray support for associative arrays

前端 未结 2 1631
感动是毒
感动是毒 2021-02-19 10:56

Is there a better (built in?) way to mix observableArray and associative arrays?

viewModel = {
    a: ko.observableArray(),
    a_assoc: {},
    add_item: functi         


        
相关标签:
2条回答
  • 2021-02-19 11:27

    Typically, you would do something like this in Knockout:

    var viewModel = {
        a: ko.observableArray(["a","b","c","d"]),
        add_item: function() {
           this.a.push("new" + this.a().length);   
        }
    };
    
    viewModel.a_assoc = ko.dependentObservable(function() {
        var result = {};
        ko.utils.arrayForEach(this.a(), function(item) {
           result[item] = 1;
        });
        return result;
    }, viewModel);
    

    So, you have a dependentObservable that maps your array to an object. Note that each time that the original array is updated, the object is rebuilt. So, it is less efficient than the method in your post, but unless your object is substantially big, it is doubtful that it would cause a performance issue.

    Sample here: http://jsfiddle.net/rniemeyer/PgceN/

    0 讨论(0)
  • 2021-02-19 11:37

    I think it is best to use an associative array under the hood for performance. You also (as you alluded to) need to use an observableArray to be able to track changes (because that's how knockout works).

    If you're seeking a 'knockout friendly' associative array you probably want a way to track changes to the item (and thus affect dependency chains).

    http://jsfiddle.net/rz41afLq/2/

    Here's what I came up with that suited my needs. Basically you store a key value pair in the observableArray and use a standard associative array to store a copy for lookup purposes.

    // VIEW MODEL
    var viewModel = {
    
        // we have to use observable array to track changes
        items: ko.observableArray([]),
    
        // also use associative array for performance
        _assoc: {},
    
        update_item: function(key, value) {
    
            // use a true assoc array for performance
            // _assoc[key] = ko.observable(value)
            if (viewModel._assoc[key])
            {
                // update observable (overwriting existing item)
                viewModel._assoc[key].value(value);
            }
            else { 
                // Important: See how we wrap value with an observable to detect changes
                this.items.push(viewModel._assoc[key] = { key: key, value: ko.observable(value) });
            }
        }
    };
    

    So you save your dogs like this:

    update_item('dogs', ['kim', 'abbey', 'goldie', 'rover']);
    update_item('dogs', ko.observableArray(['kim', 'abbey', 'goldie', 'rover']));
    

    (The second is only required if you are planning on calling pop() or push() on the list of dogs and want to update the UI. You can of course call update_item to completely update the item at any time in which case it doesn't need to be observable)

    To lookup a value, you dynamically create a computed to go fetch it :

    var dogs = getValue('dogs');
    

    Then as soon as the value indexed as 'dogs' in the associative array changes then the observable dogs() will update (and can be chained). This dogs observable can be bound to the UI of course

    var getValue = function(key) { return ko.pureComputed(function() 
    {
        // reevaluate when item is added or removed to list
        // not necessary if the value itself changes
        viewModel.items();                                                      
    
        var item = viewModel._assoc[key];
        return (item == null) ? null : item.value();
    
    }, viewModel);
    
    0 讨论(0)
提交回复
热议问题