web-dev-qa-db-fra.com

Knockout js boucle jusqu'à une valeur

J'ai un entier observable, pages, et je veux boucler jusqu'à la valeur des pages dans le code HTML par exemple.

pages = ko.observable(3) 

produit

<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul> 

Existe-t-il une liaison qui convient à cela? 

31
Tom

Vous pouvez écrire quelque chose comme ceci:

<ul data-bind="foreach: new Array(pages())">
    <li data-bind='text: $index()+1'></li>
</ul> 

Voici le violon en marche: http://jsfiddle.net/L8Uy5/

76
Artem Vyshniakov

La réponse de Artem Vyshniakov est un excellent moyen rapide de faire fonctionner cette vue dans la vue sans changer le modèle de vue. Toutefois, si vous envisagez d'étendre rapidement la configuration, ou si vous n'aimez pas avoir (ce qui est sans doute une logique testable par unité) new Array(pages()) à votre avis, voici une solution alternative. Un avantage supplémentaire pourrait être que vous pouvez également encapsuler le bit $index + 1:

function ViewModel() {
  var self = this;
  
  self.pages = ko.observable(3);
  
  self.pageArray = ko.computed(function() {
    var list = [];
    var length = parseInt(self.pages(), 10); // the <input> makes `pages` a string!
    for (var i = 1; i <= length; i++) {
      list.Push(i);
    }
    return list;
  });
}

ko.applyBindings(new ViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>

<input data-bind="textInput: pages" type="number">

<ul data-bind="foreach: pageArray">
  <li data-bind="text: $data"></li>
</ul>

Le code pageArray est généralement volumineux car (a) pages devient une chaîne à cause de l'entrée, qui pourrait être mieux résolue en transformant pages en calculable inscriptible, et (b) parce que j'ai choisi d'utiliser un for boucle/basic solution pour créer la gamme (sur laquelle vous pourriez améliorer ).

Voici une version suggérée qui améliore les deux points:

function ViewModel() {
  var self = this, 
      _pages = ko.observable(3);
  
  self.pages = ko.computed({
    read: () => _pages(),
    write: newVal => _pages(parseInt(newVal, 10))
  });
  
  self.pageArray = ko.computed(() => _.range(1, _pages() + 1));
}

ko.applyBindings(new ViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>

<input data-bind="textInput: pages" type="number">

<ul data-bind="foreach: pageArray">
  <li data-bind="text: $data"></li>
</ul>

Quoi qu'il en soit, pageArray et son contenu sont maintenant entièrement testables par unité et accessibles à d'autres bits de la logique du modèle de vue. (Si vous n'en avez pas besoin, par exemple si vous n'échafaudez qu'une vue, je vous prierais d'aller avec l'autre réponse).

2
Jeroen

Si vous avez juste besoin d'une simple boucle for, vous pouvez faire quelque chose comme ceci:

<select name="something"
    data-bind="foreach: new Array(10)">
    <option data-bind="text: $index()+1, value: $index()+1"></option>
</select>

Vous pouvez spécifier le nombre d'éléments en remplaçant (10) par n'importe quel nombre ..__ Cela produira un simple menu déroulant contenant des nombres de 1 à 10.

1
Zankar