wake-up-neo.com

Knockout.js - foreach-Bindung - testet das letzte Element

Ich verwende die folgende Vorlage:

<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>

Ich erhalte diesen Fehler in der Konsole:

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

Ist meine einzige Option, meinem Viewmodel eine Funktion hinzuzufügen, die true/false zurückgibt, wenn das übergebene Element das letzte im Array ist?

40
Jonathan

Ich habe das Problem vereinfacht, aber dies jsFiddle zeigt eine mögliche Lösung.

"if" -Bindung:

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

Containerless "if" Bindung:

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

Sie können $index innerhalb einer foreach-Bindung verwenden, um den Index des aktuell gebundenen Elements abzurufen. Vergleichen Sie dies mit der ursprünglichen Sammlung des übergeordneten Elements.

Siehe HIER für weitere Informationen zu Bindungskontexten.

77
Brett Postin

Mir ist aufgefallen, dass es eine Reihe von Anfragen nach Erweiterungen von KO gibt, um die reservierten $length, $last oder $array -Eigenschaften in der foreach-Bindung zu unterstützen, obwohl dies aus verschiedenen Gründen (häufig aus Leistung) Sie haben es nicht in die Codebasis geschafft.

Wenn jemand daran interessiert ist, diese Elemente mithilfe einer benutzerdefinierten Bindung für einen bestimmten Fall verfügbar zu machen, folgt ein einfaches Beispiel, bei dem die Variable $length verfügbar gemacht wird, um eine "hübsche" Liste zu drucken. 
Sie verwenden einfach forEachWithLength überall, wo Sie normalerweise foreach verwenden würden.

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

Verwendungsbeispiel:

<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>

Eingabe:["One", "Two", "Three", "Four"]

Ausgabe:One, Two, Three and Four

Fiddle

Weitere Lektüre

9
mwielbut

Wenn Sie NICHT mit der Option as in der foreach-Bindung verwenden, gehen Sie zur meistbewerteten Antwort auf diese Frage

Wenn Sie DO verwenden, verwenden Sie den Operator as in der foreach-Bindung. dann wird diese Antwort NICHT funktionieren.

Hier ist die Lösung in diesem Fall

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

Das Geheimnis beim Ersetzen von $parent.data() durch den Namen des beobachtbaren Arrays, das Sie verwenden In meinem Fall hieß es Items, also habe ich $parent.data() durch $parent.Items() ersetzt.

NOTE _ ​​Diese Lösung funktioniert in allen Fällen, falls Sie die Option as verwenden oder nicht, 
aber im ersten Fall löst es etwas, das die meistbewertete Antwort nicht gelöst hat.

3
Hakam Fostok

Versuche Folgendes:

  1. Verwenden Sie $root anstelle von $parent
  2. Bereiten Sie das letzte Element im Voraus vor und übergeben Sie dieses Element als zusätzlichen Parameter an Ihre Vorlage. 
  3. Das letzte zu beobachtende Element einkapseln. 
0
Madman