2012-02-07 21 views
38

Sto usando la seguente configurazione:Knockout.js - vincolante foreach - prova se ultimo elemento

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

ottengo questo errore nella console:

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

è la mia unica opzione per aggiungere un funzione al mio viewmodel che restituisce true/false se l'elemento passato è l'ultimo nella matrice?

+0

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

+2

Si potrebbe voler provare a riprodurre questo in jsFiddle. L'unica cosa che ho notato è che ti manca una chiusura del tag 'p', che può causare problemi nel binding/context. Puoi mantenere pulito il tuo view mettendo un osservabile calcolato o una funzione sul tuo modello di vista per aiutare a determinare l'ultimo elemento. –

risposta

0

provare quanto segue:

  1. Uso $root invece di $parent
  2. Preparare l'ultima voce in anticipo e passare questa voce per il modello come parametro aggiuntivo.
  3. incapsulare l'ultimo elemento a osservabile.
73

Ho semplificato il problema, ma questo jsFiddle dimostra una possibile soluzione.

"se" vincolante:

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

containerless "se" vincolante:

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

È possibile utilizzare $index all'interno di un foreach vincolante per ottenere l'indice del momento oggetto legato. Usalo per confrontarlo con la raccolta originale del genitore.

Vedi HERE per ulteriori informazioni riguardanti i contesti vincolanti.

+1

Sfortunatamente, se si usa l'opzione 'as',' $ data' non è anche vincolato .. solo un "gotcha". – user2246674

+0

Questo non ha funzionato per me, penso che forse b/c sono in knockout v 2.2.1. Tuttavia, ciò che segue ha funzionato (sostituisci MyWingDings con il nome del tuo oggetto array, ovviamente). data-bind = "visible: $ index() <$ parent.MyWingDings.length - 1" – Sean

+0

@ user2246674 vedere ** [mia risposta] (http://stackoverflow.com/a/076/4390133) ** in caso stai usando l'opzione 'as' –

8

ho notato che ci sono un certo numero di richieste di miglioramenti KO per sostenere le $length, $last, o $array proprietà riservati nel legame foreach anche se, per una serie di motivi (spesso di prestazioni), che non hanno fatto in codebase.

Se qualcuno è interessato a esporre questi elementi per un caso specifico utilizzando una consuetudine vincolante, ecco un semplice esempio di esporre la variabile $length per stampare una lista "bella".
È sufficiente utilizzare forEachWithLength ovunque si usa normalmente foreach.utilizzo

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

Esempio:

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

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

uscita:One, Two, Three and Four

Fiddle

Further reading

2

Se siete NON utilizzando as opzione nel foreach vincolante, poi andare al most-upvoted answer to this question.

Se si è DO utilizzando l'operatore as nell'associazione foreach. allora quella risposta sarà NON lavoro.

Ecco la soluzione in questo caso

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

Il segreto con la sostituzione del $parent.data() con il nome della matrice osservabile in uso Nel mio caso è stato chiamato Items, così ho sostituito il $parent.data() con $parent.Items()

NOTAquesta soluzione sta lavorando in tutti i casi, nel caso in cui si utilizza as opzione o nessuna t,
ma nel primo caso risolve qualcosa che la risposta più scalettata non ha risolto

Problemi correlati