2012-02-07 14 views
38

Używam następujący szablon:Knockout.js - wiązanie foreach - test jeśli ostatni element

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

otrzymuję ten błąd w konsoli:

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

jest moim jedynym rozwiązaniem, aby dodać funkcji do mojego viewmodel, który zwraca true/false, jeśli przekazany element jest ostatni w tablicy?

+0

http://memegenerator.net/instance/14211604 – Jonathan

+2

Możesz spróbować odtworzyć to w jsFiddle. Zauważyłem tylko, że brakuje ci zamknięcia znacznika 'p', co może powodować problemy w wiązaniu/kontekście. Możesz zachować czystość widoku, umieszczając obliczone obserwowalne lub funkcję w modelu widoku, aby pomóc w określeniu ostatniego elementu. –

Odpowiedz

0

Spróbuj wykonać następujące czynności:

  1. Zastosowanie $root zamiast $parent
  2. Przygotować ostatni element z góry i przekazać ten element do szablonu jako dodatkowy parametr.
  3. Kapsuł ostatni element do obserwowania.
73

Uprościłem problem, ale ten jsFiddle demonstruje możliwe rozwiązanie.

"czy" wiązanie:

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

Containerless "czy" wiązanie:

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

Można użyć $index w foreach wiązania, aby uzyskać indeks aktualnie związany przedmiot. Użyj tego, aby porównać z oryginalnym zbiorem rodzica.

Aby uzyskać więcej informacji dotyczących kontekstów powiązań, zobacz temat HERE.

+1

Niestety, jeśli użyjesz opcji 'as',' $ data' również nie zostanie powiązane ... po prostu "gotcha". – user2246674

+0

To nie działa dla mnie, myślę, że może b/c jestem na nokaut v 2.2.1. Jednak zadziałały następujące rzeczy (oczywiście zamień MyWingDings na nazwę twojego obiektu tablicy). data-bind = "visible: $ index() <$ parent.MyWingDings.length - 1" – Sean

+0

@ user2246674 zobacz ** [moja odpowiedź] (http://stackoverflow.com/a/076/4390133) ** w przypadku używasz opcji 'as' –

8

zauważyłem istnieje szereg wniosków o ulepszeniach KO wspierać $length, $last lub $array zastrzeżone właściwościach w wiązaniu foreach choć z różnych powodów (często wydajności), że nie znalazły się w baza kodów.

Jeśli ktoś jest zainteresowany ekspozycją tych elementów dla konkretnego przypadku za pomocą niestandardowego powiązania, oto prosty przykład ujawnienia zmiennej $length w celu wydrukowania "ładnej" listy.
Po prostu używasz forEachWithLength wszędzie, gdzie normalnie używasz 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); 
    } 
}; 

Przykład użycia:

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

Wejście:["One", "Two", "Three", "Four"]

wyjściowa:One, Two, Three and Four

Fiddle

Further reading

2

Jeśli jesteś NIE użyciu as opcję w foreach wiążącej, a następnie przejść do most-upvoted answer to this question.

Jeśli jesteś DO przy użyciu operatora as w oprawie foreach. wtedy ta odpowiedź zadziała NOT.

Oto rozwiązanie w tym przypadku

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

Sekret z wymianą $parent.data() z nazwą obserwowalnych tablicy używanego W moim przypadku to nazwano Items, więc zastąpił $parent.data() z $parent.Items()

UWAGAto rozwiązanie działa we wszystkich przypadkach, w przypadku korzystania z opcji lub nie as t,
, ale w pierwszym przypadku rozwiązuje coś, czego najbardziej uprzywilejowana odpowiedź nie rozwiąże

Powiązane problemy