3

ko.computed 関数からバインドされた要素にアクセスすることは可能ですか?

この疑似コードのようなもの (わかりやすくするために簡略化しています):

<h1 id="id1" data-bind="visible: myComputed">
<h1 id="id2" data-bind="visible: myComputed">
<h1 id="id3" data-bind="visible: myComputed">

...

self.myComputed = ko.computed(function(){
        return <BOUND_ELEMNT>.id == 'id2';
    });

2 番目の要素のみが表示されます。

注:要素ごとに個別に計算できることは承知していますが、私の場合は不可能です。

編集:

わかりました-より正確な例を挙げます。以下は私が持っているものと似ています:

<section id="id1" data-bind="visible: myComputed1">A lot of code</section>
<section id="id2" data-bind="visible: myComputed2">different lots of code</section>
<section id="id3" data-bind="visible: myComputed3">Other lots of code</section>

...

// This field's value changes over time (between 'id1', 'id2' and 'id3').
// Some complex logic changes this field,
// and as a result only one h1 is showing at a time.
self.myField = ko.observable();
self.myComputed1 = ko.computed(function(){
        return self.myField() == 'id1';
    });
self.myComputed2 = ko.computed(function(){
        return self.myField() == 'id2';
    });
self.myComputed3 = ko.computed(function(){
        return self.myField() == 'id3';
    });

これは DRY 原則の醜い違反であり、リファクタリングする方法を見つけたいと考えています。上記の疑似コードで解決するかもしれませんが、提案をお待ちしています...

4

3 に答える 3

3

短く単純化された例を作成しましたが、これは通常素晴らしいものです。ただし、代わりにXY 問題を導入したように感じます。そのため、この回答は役立つ場合とそうでない場合があります。

ViewModelのViewに依存関係を導入しようとしています。それは逆のはずです!このようなものはより理にかなっています:

<h1 data-bind="visible: myComputed, attr { id: myId }"></h1>

ID を設定するためのattr バインディングの使用に注意してください。ViewModel はそれに応じて構築する必要があります。

var activeHeaderId = 'id2';

var viewModel = function(id) {
    var self = this;

    self.myId = ko.observable(id);

    self.myComputed = ko.computed(function() {
        return self.myId() === activeHeaderId;
    });
}
于 2013-04-30T10:01:11.127 に答える
1

オブザーバブルを使用して可視性をトリガーするカスタム バインディング ハンドラーを作成します。このようなもの:

ko.bindingHandlers.idVisible = {
    update: function(element, valueAccessor) {
        var idUnwrapped = ko.utils.unwrapObservable(valueAccessor());
        if(idUnwrapped == $(element).attr('id'))
        {
            $(element).show();
        }
        else
        {
            $(element).hide();
        }
    }
};

HTML を変更します。

<h1 id="id1" data-bind="idVisible: headerId">Header 1</h1>
<h1 id="id2" data-bind="idVisible: headerId">Header 2</h1>
<h1 id="id3" data-bind="idVisible: headerId">Header 3</h1>

サンプル ビュー モデル:

function ViewModel() {
    var self = this;

    self.headerId = ko.observable('id1');
}
var vm = new ViewModel();
ko.applyBindings(vm);

これは、2 秒後に headerId を変更するデモを含む jsFiddle です: http://jsfiddle.net/psteele/cq9GU/

于 2013-04-30T15:00:38.943 に答える
1

注:質問の最初の部分に対する回答として、他の回答を残しておきます。他のユーザーがこの質問に出くわすのに役立つかもしれません。

更新の質問は次のとおりです。

これは DRY 原則の醜い違反であり、リファクタリングする方法を見つけたいと考えています。

OP は、コメントで、特定の例に焦点を当てた回答が優先されることを示します。サンプル コードは、DRY に違反しないように簡単にリファクタリングできます。(追伸。この構造を望む背後にある「理由」は非常に重要だと思いますが、それは、与えられたサンプルのコンテキストで質問に答えるのを妨げません。)


方法 1 -h1ビューに 1 つ - ビューモデルに 1 つのアイテム

次のビューを使用します。

<h1 data-bind="attr: {id: myField}">

このViewModelで:

self.myField = ko.observable();

非常にDRYで、機能的にはほぼ同等です(ただし、他の2つのh1要素は見えないだけでなく、DOMにもありません)。


方法 2 -h1ビュー内の複数の s - ViewModel 内の複数のアイテム

ビューをリスト構造にリファクタリングします ( foreach バインディングの注 4 を参照)。

<!-- ko foreach: items -->
<h1 data-bind="attr: {id: myId}, 
               text: itemName, 
               visible: $root.currentItem().myId() === myId()">
</h1>
<!-- /ko -->

次の ViewModel を使用します。

var item = function(nr) {
    this.itemName = ko.observable("Item number " + nr);
    this.myId = ko.observable("id" + nr);
}

var viewModel = function() {
    this.items = ko.observableArray([new item(1), new item(2), new item(3)]);
    this.currentItem = ko.observable();
}

デモについては、このフィドルを参照してください。


方法 3 -h1ビュー内の 1 つ - ビューモデル内の複数のアイテム

この方法では、方法 2 のセットアップと同様にリストを使用しますが、現在のアイテムのみをレンダリングします。ビューはwithバインディングを利用します:

<!-- ko with: currentItem -->
<h1 data-bind="attr: {id: myId}, text: itemName"></h1>
<!-- /ko -->

ViewModel は方法 2 と同じです。デモについては、このフィドルを参照してください。

于 2013-04-30T13:19:58.897 に答える