簡體   English   中英

Knockout.js:將嵌套的可觀察對象與映射插件一起使用

[英]Knockout.js: Using nested observables with mapping plugin

我正在構建一個側邊欄以過濾主視圖,例如John Lewis的側邊欄。 我的代碼正常工作,但效果不佳。

我知道在類似的行上有幾個SO問題,但是我不太了解自己的用例。

我需要從服務器(例如,通過JSON)獲取復選框的名稱,以便在ShopView上動態創建observableArrays。

情況如下:

var data = {
    'gender' : [ ],
    'color' : [ ]
};

var filterMapping = {
    create: function( obj ) {
        return ko.observableArray( obj.data );
    }
}

var ShopView = new function() {

    var self = this;

    ko.mapping.fromJS( { filters: data }, filterMapping, self );

    // this is the bit I don't like
    this.filterChange = ko.computed(function () {
        for( var key in self.filters )  {
            var obj = self.filters[key]; 
             if( ko.isObservable(obj)){
                obj();                 
             }             
        }
    });

    this.filterChange.subscribe( function( ) {
        //make AJAX request for products using filter state
    });

}

我的HTML外觀如您所願:

性別

    <ul>
        <li><input type="checkbox" value="male" data-bind="checked: filters.gender" />Male</li>
        <li><input type="checkbox" value="female" data-bind="checked: filters.gender" />Female</li>
    </ul>

正如我說的那樣,它可以工作,但是效果不是很好。 在理想的世界中,我可以訂閱this.filters,例如

this.filters.subscribe( function() { 
    //make AJAX request for products using filter state
});

注意:我不打算在客戶端進行過濾-當動態綁定的復選框更改時,只需更新我的視圖模型即可。

有任何想法嗎? 謝謝!

首先,應將映射插件視為代碼復制的輔助工具。 我認為將映射插件本身視為解決方案並不是一個好主意。 至少不是直接。 由於我們看不到您正在使用的模型,因此它也會掩蓋您在SO上發布代碼時發生的情況。 只是一個想法。

現在,如果您想從服務器獲取動態過濾器,並使用它們來過濾項目列表(就像在商店中一樣),我會這樣做(在這里是小提琴 ):

var FilterOption = function(name) {
    this.name = name;
    this.value = ko.observable(false);
};

var Filter = function(data) {
    var self = this;
    self.name = data.name;
    options = ko.utils.arrayMap(data.options, function(o) {
        return new FilterOption(o);
    });
    self.options = ko.observableArray(options);
    self.filteredOptions = ko.computed(function() {
        var options = []
        ko.utils.arrayForEach(self.options(), function(o) {
            if (o.value()) options.push(o.name);
        });
        //If no options, false represents no filtering for this type
        return options.length ? options : false;
    });
};

var ViewModel = function(data) {
    var self = this;
    self.items = ko.observableArray(data.items);
    filters = ko.utils.arrayMap(data.filters, function(i) {
        return new Filter(i);
    });
    self.filters = ko.observableArray(filters);
    self.filteredItems = ko.computed(function() {
        //Get the filters that are actually active
        var filters = ko.utils.arrayFilter(self.filters(), function(o) {
            return o.filteredOptions();
        });
        //Remove items that don't pass all active filter
        return ko.utils.arrayFilter(self.items(), function(item) {
            var result = true;
            ko.utils.arrayForEach(filters, function(filter) {
                var val = item[filter.name.toLowerCase()];
                result = filter.filteredOptions().indexOf(val) > -1;
            });
            return result;
        });
    });
};

下一步顯然是增加對具有多個屬性(但具有options屬性)的項目的支持,但這應該給您基本的思想。 您有一個過濾器列表,每個過濾器帶有任意數量的選項(累加堆疊),並且使用計算項目數組來存儲過濾項目的結果。


編輯 :要使用ajax訂閱獲取項目,您可以將FilteredItems道具替換為獲取選定過濾器的計算對象,然后訂閱它,如下所示:

var ViewModel = function(data) {
    var self = this;
    self.items = ko.observableArray(data.items);
    filters = ko.utils.arrayMap(data.filters, function(i) {
        return new Filter(i);
    });
    self.filters = ko.observableArray(filters);
    self.selectedFilters = ko.computed(function() {
        ko.utils.arrayFilter(self.filters(), function(o) {
            return o.filteredOptions();
        });
    });
    self.selectedFilters.subscribe(function() {
        //Ajax request that updates self.items()
    });
};

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM