46 votes

Knockout.js - liaison foreach - test si dernier élément

J'utilise le modèle suivant :

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

J'obtiens cette erreur dans la 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());}

Ma seule option est-elle d'ajouter une fonction à mon modèle de vue qui renvoie vrai/faux si l'élément passé est le dernier dans le tableau ?

0 votes

2 votes

Vous pouvez essayer de reproduire ce phénomène dans jsFiddle. La seule chose que j'ai remarquée, c'est qu'il manque la fermeture de la balise p ce qui peut causer des problèmes de liaison/contexte. Vous pouvez garder votre vue plus propre en mettant un observable calculé ou une fonction sur votre modèle de vue pour aider à déterminer le dernier élément.

89voto

Brett Postin Points 2502

J'ai simplifié le problème, mais ceci jsFiddle démontre une solution possible.

liaison "si" :

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

Liaison "si" sans conteneur :

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

Vous pouvez utiliser $index dans un foreach pour obtenir l'index de l'élément actuellement lié. Utilisez-le pour comparer avec la collection originale du parent.

Ver ICI pour plus d'informations sur les contextes de liaison.

1 votes

Malheureusement, si vous utilisez le as option, $data n'est pas également lié c'est juste un "piège".

0 votes

Cela n'a pas fonctionné pour moi, je pense que c'est peut-être parce que je suis sur knockout v 2.2.1. Cependant, la méthode suivante a fonctionné (remplacez MyWingDings par le nom de votre objet tableau, bien sûr). data-bind="visible : $index() < $parent.MyWingDings.length - 1"

0 votes

@user2246674 voir ma réponse au cas où vous utiliseriez as option

10voto

mwielbut Points 624

J'ai remarqué qu'il y a un certain nombre de demandes d'améliorations à apporter à KO pour qu'il prenne en charge le système de gestion de l'information. $length , $last o $array les propriétés réservées dans le foreach contraignantes bien que, pour diverses raisons (souvent liées à la performance), elles n'aient pas été intégrées dans la base de code.

Si quelqu'un est intéressé par l'exposition de ces éléments pour un cas spécifique en utilisant une liaison personnalisée, voici un exemple simple d'exposition de l'élément $length afin d'imprimer une "jolie" liste.
Il suffit d'utiliser forEachWithLength partout où vous utiliseriez normalement 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);   
    }
};

Exemple d'utilisation :

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

Entrée : ["One", "Two", "Three", "Four"]

Sortie : One, Two, Three and Four

Violon

Autres lectures

0 votes

Cela ne fonctionne pas vraiment si vous avez un observableArray qui est modifié dynamiquement. L'ajout d'un élément au tableau d'observables ne réévalue pas les modèles qui ont déjà été rendus. Exemple dérivé de votre fiddle : jsfiddle.net/ek4vujy7

4voto

Hakam Fostok Points 4765

Si vous êtes PAS en utilisant as dans l'option foreach puis passez à la réponse la plus votée à cette question .

Si vous êtes DO en utilisant as dans les foreach alors cette réponse sera PAS travail.

Voici la solution dans ce cas

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

Le secret pour remplacer le $parent.data() avec le nom du tableau d'observables que vous utilisez.
Dans mon cas, il s'appelait Items J'ai donc remplacé le $parent.data() con $parent.Items()

Note cette solution fonctionne dans tous les cas, ( au cas où vous utiliseriez as option dans foreach ou non )

0 votes

Comment obtenir le dernier indice dans la boucle imbriquée ?

0voto

Madman Points 1302

Essayez ce qui suit :

  1. Utilisez $root au lieu de $parent
  2. Préparez le dernier élément à l'avance et passez cet élément à votre modèle comme paramètre supplémentaire.
  3. Encapsuler le dernier élément en observable.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X