1

たとえばJohn Lewisのもののように、メイン ビューをフィルタリングするサイドバーを構築しています。コードは機能していますが、きれいではありません。

同様の行にいくつかのSOの質問があることは知っていますが、自分のユースケースを完全に理解することはできません.

ShopView で observableArrays を動的に作成するには、サーバーから (たとえば JSON 経由で) チェックボックスの名前を取得する必要があります。

方法は次のとおりです。

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
});

NBクライアント側でフィルタリングを実行しようとしているわけではありません。動的にバインドされたチェックボックスが変更されたときにビューモデルを更新するだけです。

何か案は?ありがとう!

4

1 に答える 1

1

まず、マッピングプラグインは、コードの重複を支援するものとして扱う必要があります。マッピングプラグインをそれ自体がソリューションとして考えるのは良い考えではないと思います。少なくとも直接ではありません。また、作業中のモデルが表示されないため、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;
        });
    });
};

次の明らかなステップは、複数のプロパティ、またはオプションのプロパティを持つアイテムのサポートを追加することですが、これで基本的な考え方がわかります。フィルタのリストがあり、それぞれに任意の数のオプション(追加的にスタック)があり、計算されたアイテムの配列を使用して、アイテムのフィルタリングの結果を格納します。


編集: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()
    });
};
于 2013-01-23T20:19:46.180 に答える