0

以下を実装するためのクリーンな方法を探しています。ボタンが 5 つあるとします。

(犬) - (猫) - (魚) - (鳥) - (その他)

私の ViewModel では、これらのボタンは分類として表されます。そのため、Dog ボタンをクリックすると、ViewModel のオブザーバブルを Dog に設定する必要があります (これは、各ボタンのクリック バインディングによって行われます)。

また、ボタンの 1 つが切り替えられたときに特定のスタイルを表示したい (ボタンの css バインディングによって行われる):

(犬) - (猫) - (魚) - (鳥) - (その他)

今のところ、これはボタンをラジオボタングループに変える必要があるようです。それに加えて、「その他」ボタンをクリックすると、ユーザーが「ライオン」などのカスタム値を指定できる小さなポップオーバー (ブートストラップ) も表示したいと考えています。他のボタンをクリックすると、ポップオーバーが閉じます。

各ボタンに、次のようなバインディングを追加できます。

{ css: { 'toggled': classficationMatches('Dog') }, 
     popover: { action: 'close', id: 'mypopover' },
     click: { click:setClassification.bind($data, 'Dog') }

しかし、これは汚れているように感じます。カスタムハンドラーを作成して、次のように使用することをお勧めします。

{ toggleClassification: { type: 'Dog', popover: 'mypopover' } }

ここで、ポップオーバーを表示するかどうかを決定するのは ViewModel 次第であり、バインディングには、css バインディング、クリック、およびポップオーバー バインディングをボタンに追加するすべてのロジックが含まれます。

カスタムバインディングでいくつかのことを試し始めましたが、このコードはさらに悪いようです:

ko.bindingHandlers["toggleClassification"] = {
    init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        var classification = $(element).attr('data-type');
        var selector = ko.utils.unwrapObservable(valueAccessor());

        var pickerViewModel = new SimpleFilterSpecializationPickerViewModel(element, selector);

        // Whenever we click the button, show the popover.
        ko.utils.registerEventHandler(element, "click", function () {
            // Hide the popup if it was visible.
            if (pickerViewModel.isVisible()) {
                pickerViewModel.hide();
            }
            else {
                var requireInit = !pickerViewModel.loaded();

                // Show the popover.
                pickerViewModel.show();

                // The first time we need to bind the popover to the view model.
                if (requireInit) {
                    ko.applyBindings(viewModel, pickerViewModel.getPopoverElement());

                    // If the classification changes, we might not want to show the popover.
                    viewModel.isClassification(classification).subscribe(function () {
                        if (!viewModel.isClassification(classification)()) {
                            pickerViewModel.hide();
                        }
                    });
                }
            }

            $('button[data-popoverclose]').click(function () {
                $(element).popover('hide');
            });
        });
    }
};



ko.bindingHandlers["toggleClassification"] = {
    init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {

        // Store the current value on click.
        $(element).click(function () {
            var observable = valueAccessor();
            viewModel.setClassification(observable);
        }); 

        // Update the css of the button.
        ko.applyBindingsToNode(element, { css: { 'active': viewModel.isClassification(valueAccessor()) } }, viewModel);
    }
};

ほとんどの「ロジック」を ViewModel で実行できるように、バインディングをクリーンアップする方法についてのヒントはありますか?

4

1 に答える 1

0

この「ダーティ」バインディングは、HTML
ko.applyBindingsToNode(Element element, Object bindings, Object viewModel)
などを使用してプログラムで追加できます。

data-bind="toggleClassification: { type: 'Dog', popover: 'mypopover' }"  

JS

ko.bindingHandlers["toggleClassification"] = 
{
    init: function (element, valueAccessor, allBindings, viewModel, bindingContext) 
    {
        var type = valueAccessor().type;       // 'Dog'
        var popover = valueAccessor().popover; // 'mypopover'
        var binding = { 
                         css: { 'toggled': classficationMatches(type) }, 
                         popover: { action: 'close', id: popover },
                         click: { click:setClassification.bind(bindingContext.$data, type) }
                      };
        ko.applyBindingsToNode(element, binding , viewModel);
    }
};
于 2013-11-12T21:22:30.110 に答える