web-dev-qa-db-ja.com

Knockout.js-foreachバインディング-最後の要素かどうかをテストする

次のテンプレートを使用しています。

<div class="datatypeOptions" data-bind="if: $data.datatypeTemplate().allowOptions">
    <h3>Allowed responses</h3>

    <p data-bind="if: $data.datatypeTemplate().datatypeOptions().length == 0">There are no responses for this question, yet. <a href="#" data-bind="click: function(d, e){$root.addDatatypeOption($data.datatypeTemplate());}">Add one</a>
    <ul data-bind="foreach: $data.datatypeTemplate().datatypeOptions()">
        <li>
            <a href="#" data-bind="text: name, click: $root.selectedDatatypeOption, visible: $data !== $root.selectedDatatypeOption()"></a>
            <input data-bind="value: name, visibleAndSelect: $data === $root.selectedDatatypeOption(), event: { blur: $root.clearDatatypeOption }, executeOnEnter: { callback: function(){ $root.addDatatypeOption($parent.datatypeTemplate()); } }" />
            //I want to show this a tag only if $data is the last element in the array.
Problem here ===>  <a href="#" data-bind="if: $data == $parent.datatypeTemplate().datatypeOptions()[ $parent.datatypeTemplate().datatypeOptions().length - 1 ], click: function(d, e){$root.addDatatypeOption($data.datatypeTemplate());}"><img src='/static/img/icons/custom-task-wizard/black/plus_12x12.png' title='Add option'></a>
        </li>
    </ul>
</div>

コンソールにこのエラーが表示されます。

Uncaught Error: Unable to parse bindings.
Message: TypeError: Object [object Object] has no method 'datatypeTemplate';
Bindings value: if: $data == $parent.datatypeTemplate().datatypeOptions()[ $parent.datatypeTemplate().datatypeOptions().length - 1 ], click: function(d, e){$root.addDatatypeOption($data.datatypeTemplate());}

渡された要素が配列の最後にある場合にtrue/falseを返す関数をビューモデルに追加する唯一のオプションですか?

41
Jonathan

問題を単純化しましたが、これ jsFiddle は可能な解決策を示しています。

"if"バインディング:

<div data-bind="if: ($index() === ($parent.data().length - 1))">I'm the last element</div>

コンテナなしの「if」バインディング:

<!-- ko if: ($index() === ($parent.data().length - 1)) -->
<div>I'm the last element again</div>
<!-- /ko -->

foreachバインディング内で$indexを使用して、現在バインドされているアイテムのインデックスを取得できます。これを使用して、親の元のコレクションと比較します。

バインディングコンテキストの詳細については、 [〜#〜] here [〜#〜] を参照してください。

79
Brett Postin

foreachバインディングの$length$last、または$array予約済みプロパティをサポートするために、KOの機能強化を求める多くの要求があることに気づきましたが、理由(多くの場合パフォーマンス)のために、彼らはそれをコードベースに入れていません。

カスタムバインディングを使用して特定のケースのこれらの要素を公開することに興味がある場合、「きれいな」リストを印刷するために$length変数を公開する簡単な例を次に示します。
通常forEachWithLengthを使用する任意の場所でforeachを使用します。

ko.bindingHandlers.forEachWithLength = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel, context)
    {         
        return ko.bindingHandlers.foreach.init(element, valueAccessor, allBindingsAccessor, viewModel, context);
    },
    update: function (element, valueAccessor, allBindingsAccessor, viewModel, context) 
    {         
        var array = ko.utils.unwrapObservable(valueAccessor());
        var extendedContext = context.extend({"$length" : array.length });
        ko.bindingHandlers.foreach.update(element, valueAccessor, allBindingsAccessor, viewModel, extendedContext);   
    }
};

使用例:

<div data-bind="forEachWithLength: myArray">
    <span data-bind="text: $data"></span>
    <!-- ko if: ($index() < $length-2) -->, <!-- /ko -->
    <!-- ko if: ($index() === $length-2) --> and <!-- /ko -->
</div>

入力:["One", "Two", "Three", "Four"]

出力:One, Two, Three and Four

フィドル

さらに読む

10
mwielbut

asバインディングでforeachオプションを使用している[〜#〜] not [〜#〜]の場合、この質問に対する最も支持された回答

あなたが[〜#〜] do [〜#〜]の場合、asバインディングでforeach演算子を使用します。その答えは[〜#〜] not [〜#〜]は機能しません。

その場合の解決策は次のとおりです

_<div data-bind="foreach:{data: Items, as :'item'}">
    <div data-bind="if: ($index() === ($parent.Items().length - 1))">I'm the last element</div>
</div>
_

$parent.data()を使用している観測可能な配列の名前で置き換えることの秘密私の場合、Itemsという名前だったので、$parent.data() with $parent.Items()

[〜#〜] note [〜#〜]このソリューションは、asを使用している場合、すべての場合に機能していますオプションかどうか、
しかし、最初のケースでは、最も支持された答えが解決しなかった何かを解決します

3
Hakan Fıstık

以下を試してください:

  1. 使用する $root の代わりに $parent
  2. 事前に最後のアイテムを準備し、このアイテムを追加のパラメーターとしてテンプレートに渡します。
  3. 最後の要素を観測可能にカプセル化します。
0
Madman