2012-02-07 3 views
38

Я использую следующий шаблон:Knockout.js - Еогеасп связывание - тест, если последний элемент

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

Это мой единственный вариант, чтобы добавить функция для моей модели viewmodel, которая возвращает true/false, если прошедший элемент является последним в массиве?

+0

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

+2

Вы можете попытаться воспроизвести это в jsFiddle. Единственное, что я заметил, это то, что вам не хватает закрытия тэга 'p', что может вызвать проблемы в bind/context. Вы можете сохранить свой вид более чистым, поставив вычисленную наблюдаемую или функцию на вашу модель просмотра, чтобы помочь определить последний элемент. –

ответ

0

Попробуйте следующее:

  1. Использование $root вместо $parent
  2. Подготовить последний пункт заранее и передать этот пункт в шаблон в качестве дополнительного параметра.
  3. Инкапсулируйте последний элемент на наблюдаемый.
73

Я упростил проблему, но это jsFiddle демонстрирует возможное решение.

"если" связывание:

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

Containerless "если" связывание:

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

Вы можете использовать $index в foreach связывания, чтобы получить индекс в настоящее время связанный элемент. Используйте это для сравнения с исходной коллекцией родителя.

См. HERE для получения дополнительной информации о контексте привязки.

+1

К сожалению, если вы используете опцию 'as',' $ data' также не привязана .. просто «gotcha». – user2246674

+0

Это не сработало для меня, я думаю, может быть, b/c Я на нокауте v 2.2.1. Однако было выполнено следующее (замените MyWingDings на имя вашего объекта массива, конечно). data-bind = "visible: $ index() <$ parent.MyWingDings.length - 1" – Sean

+0

@ user2246674 см. ** [мой ответ] (http://stackoverflow.com/a/076/4390133) ** в случае вы используете опцию 'as' –

8

я заметил, есть целый ряд запросов на усовершенствования КО поддержать $length, $last или $array зарезервированных свойств в связывании foreach, хотя, по разным причинам (часто производительность), они не сделали это в кодовая.

Если кто-либо заинтересован в экспонировании этих элементов для конкретного случая с использованием настраиваемого связывания, вот простой пример подвержения переменной $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

Fiddle

Further reading

2

Если вы НЕ используя as опцию в foreach связывания, а затем перейти к most-upvoted answer to this question.

Если вы 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() с $parent.Items()

Примечаниеэто решение работает во всех случаях, в случае, если вы не используете as опцию или нет т,
, но в первом случае это решает что-то, что наиболее upvoted ответ не решить

Смежные вопросы