AngularJS For Loop con numeri e intervalli


252

Angular fornisce un supporto per un ciclo for usando i numeri nelle sue direttive HTML:

<div data-ng-repeat="i in [1,2,3,4,5]">
  do something
</div>

Ma se la variabile dell'ambito include un intervallo con un numero dinamico, sarà necessario creare ogni volta un array vuoto.

Nel controller

var range = [];
for(var i=0;i<total;i++) {
  range.push(i);
}
$scope.range = range;

Nel codice HTML

<div data-ng-repeat="i in range">
  do something
</div>

Funziona, ma non è necessario poiché non utilizzeremo affatto l'array range all'interno del loop. Qualcuno sa di impostare un intervallo o un normale per il valore min / max?

Qualcosa di simile a:

<div data-ng-repeat="i in 1 .. 100">
  do something
</div>

2
Ecco qualche informazione in più su questo. yearofmoo.com/2012/10/…
matsko,

Risposte:


281

Ho modificato un po ' questa risposta e ho trovato questo violino .

Filtro definito come:

var myApp = angular.module('myApp', []);
myApp.filter('range', function() {
  return function(input, total) {
    total = parseInt(total);

    for (var i=0; i<total; i++) {
      input.push(i);
    }

    return input;
  };
});

Con la ripetizione usata in questo modo:

<div ng-repeat="n in [] | range:100">
  do something
</div>

Interessante Non vedo un errore nel violino usando Chrome. Quale browser?
Gloopy,

5
Horrid! ;) Un filtro non è il modo per farlo. Dovrebbe essere un nuovo attributo che funziona con due valori. L'indice corrente e il limite superiore.
Ian Warburton,

10
@IanWarburton Sei in grado di trovare una risposta che soddisfi i tuoi criteri?
rugiada del

1
@IanWarburton: Di seguito c'è una risposta di belowmed che funziona con una direttiva, ma non riesco a farlo funzionare.
Andresch Serj

1
Avevo bisogno di un intervallo tra A e B, quindi ho cercato questa risposta jsfiddle.net/h9nLc8mk
Marcio

150

Mi è venuta in mente una versione ancora più semplice, per creare un intervallo tra due numeri definiti, ad es. 5 a 15

Guarda la demo su JSFiddle

HTML :

<ul>
    <li ng-repeat="n in range(5,15)">Number {{n}}</li>
</ul>

Controller :

$scope.range = function(min, max, step) {
    step = step || 1;
    var input = [];
    for (var i = min; i <= max; i += step) {
        input.push(i);
    }
    return input;
};

14
Devi stare attento a cose come questa. La funzione intervallo verrà chiamata più volte per ciascun elemento nell'elenco. Puoi ottenere brutte perdite di memoria e stai generando molte chiamate di funzione. Sembra quasi più facile inserire la raccolta all'interno del controller.
Lucas Holt,

1
var a; void 0 === a"veramente" indefinito.
Andlrc,

1
È possibile ridurre il colpo perfetto memorizzando nella cache i risultati tramite il modello memoizer. Non sono sicuro del costo della memoria, ma è un miglioramento. en.wikipedia.org/wiki/Memoization .
Joshua,

1
@LucasHolt Finalmente sono riuscito ad aggiornare questo esempio. Ho aggiunto una versione ottimizzata. Avrà ancora molte chiamate di funzione, ma riutilizzerà il primo risultato che lo rende molto più performante.
sqren,

93

Nient'altro che Javascript semplice (non hai nemmeno bisogno di un controller):

<div ng-repeat="n in [].constructor(10) track by $index">
    {{ $index }}
</div>

Molto utile durante il mockup


Non funziona in Angolare> 1.2.1: ho questo errore nella console Referencing "constructor" field in Angular expressions is disallowed! Expression: [].constructor(10). Forse funzionava in una versione precedente di Angular o sto facendo qualcosa di sbagliato.
AWolf

Penso di averlo provato su 1.3 o 1.4 e andava bene. Credo che abbiano migliorato il parser in modo da non rifiutare ogni accesso "costruttore" ma solo quelli veramente pericolosi (come [].slice.constructor, ad esempio , che dà accesso Function, quindi alla valutazione del codice).
Maël Nison,

Ok grazie. L'ho provato con 1.2.1 e non funzionava (la versione inclusa nel menu a discesa jsFiddle). Ma con 1.3.15 funziona. Vedi questo jsFiddle .
AWolf

Utilissimo per l'impaginazione. Grazie;)
Stranger

69

Mi è venuta in mente una sintassi leggermente diversa che mi si adatta un po 'di più e aggiunge anche un limite inferiore opzionale:

myApp.filter('makeRange', function() {
        return function(input) {
            var lowBound, highBound;
            switch (input.length) {
            case 1:
                lowBound = 0;
                highBound = parseInt(input[0]) - 1;
                break;
            case 2:
                lowBound = parseInt(input[0]);
                highBound = parseInt(input[1]);
                break;
            default:
                return input;
            }
            var result = [];
            for (var i = lowBound; i <= highBound; i++)
                result.push(i);
            return result;
        };
    });

che puoi usare come

<div ng-repeat="n in [10] | makeRange">Do something 0..9: {{n}}</div>

o

<div ng-repeat="n in [20, 29] | makeRange">Do something 20..29: {{n}}</div>

Questo è grande, ma come si fa a ottenere intorno a tutte le $digestiterazioni quando si utilizza un valore di ambito, vale a dire: ng-repeat="n in [1, maxValue] | makeRange"?
pspahn,

L'uno e due casi param trattano highBound in modo diverso, dovrebbe essere coerente
Vajk Hermecz,

31

Per chi non conosce angularjs. L'indice può essere ottenuto utilizzando $ index.

Per esempio:

<div ng-repeat="n in [] | range:10">
    do something number {{$index}}
</div>

Che, quando stai usando il pratico filtro di Gloopy, stampa:
fai qualcosa numero 0
fai qualcosa numero 1
fai qualcosa numero 2
fai qualcosa numero 3
fai qualcosa numero 4
fai qualcosa numero 5
fai qualcosa numero 6
fai qualcosa numero 7
fai qualcosa numero 8
fai qualcosa numero 9


7
Vero, ma in questo caso do something number {{n}}sarebbe anche sufficiente.
captncraig,

2
Quando provo a eseguire questo codice in Chrome, visualizzo un errore nella console: Errore: [$ injector: unpr] errors.angularjs.org/1.2.6/$injector/… ... ... su Wa.statements ( ajax.googleapis.com/ajax/libs/angularjs/1.2.6/… ) <! - ngRepeat: n in [] | intervallo: 10 -> (purtroppo l'intero errore è troppo lungo per adattarsi alla lunghezza consentita del commento, quindi ho appena copiato la prima e l'ultima riga)
Kmeixner,

1
Ho creato un esempio di Plunker del codice in modo da poterlo confrontare con il tuo codice. plnkr.co/edit/tN0156hRfX0M6k9peQ2C?p=preview
Arnoud Sietsema

21

Un modo breve per farlo sarebbe usare il metodo _.range () di Underscore.js. :)

http://underscorejs.org/#range

// declare in your controller or wrap _.range in a function that returns a dynamic range.
var range = _.range(1, 11);

// val will be each number in the array not the index.
<div ng-repeat='val in range'>
    {{ $index }}: {{ val }}
</div>

1
@jwoodward Non ha mai detto che non era un'opzione. La mia soluzione è di gran lunga la più semplice e la più testata grazie ai test unitari del loro repository. Puoi sempre estrarre js dalla libreria non mininata e includerla come funzione.
Michael J. Calkins,

4
È vero, non l'ha mai detto. Ma è generalmente una cattiva idea risolvere un problema in una libreria applicando un'altra libreria, ti impedisce solo di imparare come usare correttamente la prima libreria. Passare a un'altra libreria quando / se non esiste una soluzione valida in quella corrente.
Erik Honn,

5
Uso già lodash ovunque, questa era di gran lunga la soluzione più semplice. Grazie. Ho appena fatto $ scope.range = _.range, quindi è facile da usare in qualsiasi modello con valori di inizio / fine dinamici.
j_walker_dev

2
@ErikHonn: UnderscoreJS risolve un problema completamente diverso da AngularJS. Non esiste una buona soluzione per generare intervalli in AngularJS perché questo non è lo scopo della libreria.
AlexFoxGill,

2
Questo è vecchio, ma sicuramente usare una libreria progettata per fare cose esattamente come la creazione di un intervallo, invece di abusare di una funzione nella tua libreria attuale in modo non semantico è un modo molto migliore per andare? Sicuro che potresti imparare qualcosa, ma finirai con usi distorti di cose progettate per qualcos'altro.
Dan

20

Uso la mia ng-repeat-rangedirettiva personalizzata :

/**
 * Ng-Repeat implementation working with number ranges.
 *
 * @author Umed Khudoiberdiev
 */
angular.module('commonsMain').directive('ngRepeatRange', ['$compile', function ($compile) {
    return {
        replace: true,
        scope: { from: '=', to: '=', step: '=' },

        link: function (scope, element, attrs) {

            // returns an array with the range of numbers
            // you can use _.range instead if you use underscore
            function range(from, to, step) {
                var array = [];
                while (from + step <= to)
                    array[array.length] = from += step;

                return array;
            }

            // prepare range options
            var from = scope.from || 0;
            var step = scope.step || 1;
            var to   = scope.to || attrs.ngRepeatRange;

            // get range of numbers, convert to the string and add ng-repeat
            var rangeString = range(from, to + 1, step).join(',');
            angular.element(element).attr('ng-repeat', 'n in [' + rangeString + ']');
            angular.element(element).removeAttr('ng-repeat-range');

            $compile(element)(scope);
        }
    };
}]);

e il codice html è

<div ng-repeat-range from="0" to="20" step="5">
    Hello 4 times!
</div>

o semplicemente

<div ng-repeat-range from="5" to="10">
    Hello 5 times!
</div>

o anche semplicemente

<div ng-repeat-range to="3">
    Hello 3 times!
</div>

o solo

<div ng-repeat-range="7">
    Hello 7 times!
</div>

1
Teoricamente bello, ma l'iniezione di element.attr('ng-repeat', 'n in [' + rangeString + ']');non funziona ...
Stefan Walther,

"Io uso...". Hai davvero provato ad usarlo? L'attributo ng-repeat non verrà compilato.
Peter Hedberg,

Grazie Peter, ho aggiornato il codice. Ho usato questa direttiva in passato, ma ha comunque lasciato il mio repository di codici
pleerock

9

La soluzione senza codice più semplice era quella di avviare un array con l'intervallo e utilizzare $ index + per quanto desidero compensare:

<select ng-init="(_Array = []).length = 5;">
    <option ng-repeat="i in _Array track by $index">{{$index+5}}</option>
</select>

7

Definizione del metodo

Il codice seguente definisce un metodo range()disponibile per l'intero ambito dell'applicazione MyApp. Il suo comportamento è molto simile al range()metodo Python .

angular.module('MyApp').run(['$rootScope', function($rootScope) {
    $rootScope.range = function(min, max, step) {
        // parameters validation for method overloading
        if (max == undefined) {
            max = min;
            min = 0;
        }
        step = Math.abs(step) || 1;
        if (min > max) {
            step = -step;
        }
        // building the array
        var output = [];
        for (var value=min; value<max; value+=step) {
            output.push(value);
        }
        // returning the generated array
        return output;
    };
}]);

uso

Con un parametro:

<span ng-repeat="i in range(3)">{{ i }}, </span>

0, 1, 2,

Con due parametri:

<span ng-repeat="i in range(1, 5)">{{ i }}, </span>

1, 2, 3, 4,

Con tre parametri:

<span ng-repeat="i in range(-2, .7, .5)">{{ i }}, </span>

-2, -1.5, -1, -0.5, 0, 0.5,


6

Puoi utilizzare i filtri 'after' o 'before' nel modulo angular.filter ( https://github.com/a8m/angular-filter )

$scope.list = [1,2,3,4,5,6,7,8,9,10]

HTML:

<li ng-repeat="i in list | after:4">
  {{ i }}
</li>

risultato: 5, 6, 7, 8, 9, 10


6

Senza alcuna modifica nel controller, è possibile utilizzare questo:

ng-repeat="_ in ((_ = []) && (_.length=51) && _) track by $index"

Godere!


ho lottato per più di un giorno e finalmente solo questa sintassi ha funzionato per me
Agnel Amodia,

3

Risposta più breve: 2 righe di codice

JS (nel controller AngularJS)

$scope.range = new Array(MAX_REPEATS); // MAX_REPEATS should be the most repetitions you will ever need in a single ng-repeat

HTML

<div data-ng-repeat="i in range.slice(0,myCount) track by $index"></div>

... dov'è myCountil numero di stelle che dovrebbero apparire in questa posizione.

È possibile utilizzare $indexper qualsiasi operazione di tracciamento. Ad esempio, se si desidera stampare una mutazione sull'indice, è possibile inserire quanto segue in div:

{{ ($index + 1) * 0.5 }}

2

Utilizzando UnderscoreJS:

angular.module('myModule')
    .run(['$rootScope', function($rootScope) { $rootScope.range = _.range; }]);

Applicandolo per $rootScoperenderlo disponibile ovunque:

<div ng-repeat="x in range(1,10)">
    {{x}}
</div>

2

Molto semplice:

$scope.totalPages = new Array(10);

 <div id="pagination">
    <a ng-repeat="i in totalPages track by $index">
      {{$index+1}}
    </a>   
 </div> 

2

Ciao, puoi ottenerlo utilizzando HTML puro usando AngularJS (non è richiesta alcuna direttiva!)

<div ng-app="myapp" ng-controller="YourCtrl" ng-init="x=[5];">
  <div ng-if="i>0" ng-repeat="i in x">
    <!-- this content will repeat for 5 times. -->
    <table class="table table-striped">
      <tr ng-repeat="person in people">
         <td>{{ person.first + ' ' + person.last }}</td>
      </tr>
    </table>
    <p ng-init="x.push(i-1)"></p>
  </div>
</div>

1

Imposta Scope nel controller

var range = [];
for(var i=20;i<=70;i++) {
  range.push(i);
}
$scope.driverAges = range;

Imposta Ripeti nel file modello HTML

<select type="text" class="form-control" name="driver_age" id="driver_age">
     <option ng-repeat="age in driverAges" value="{{age}}">{{age}}</option>
</select>

1

Un miglioramento alla soluzione di @ Mormegil

app.filter('makeRange', function() {
  return function(inp) {
    var range = [+inp[1] && +inp[0] || 0, +inp[1] || +inp[0]];
    var min = Math.min(range[0], range[1]);
    var max = Math.max(range[0], range[1]);
    var result = [];
    for (var i = min; i <= max; i++) result.push(i);
    if (range[0] > range[1]) result.reverse();
    return result;
  };
});

uso

<span ng-repeat="n in [3, -3] | makeRange" ng-bind="n"></span>

3 2 1 0 -1 -2 -3

<span ng-repeat="n in [-3, 3] | makeRange" ng-bind="n"></span>

-3 -2 -1 0 1 2 3

<span ng-repeat="n in [3] | makeRange" ng-bind="n"></span>

0 1 2 3

<span ng-repeat="n in [-3] | makeRange" ng-bind="n"></span>

0 -1 -2 -3


1

Ho provato quanto segue e ha funzionato bene per me:

<md-radio-button ng-repeat="position in formInput.arrayOfChoices.slice(0,6)" value="{{position}}">{{position}}</md-radio-button>

Angolare 1.3.6


1

In ritardo alla festa. Ma ho finito per fare questo:

Nel tuo controller:

$scope.repeater = function (range) {
    var arr = []; 
    for (var i = 0; i < range; i++) {
        arr.push(i);
    }
    return arr;
}

html:

<select ng-model="myRange">
    <option>3</option>
    <option>5</option>
</select>

<div ng-repeat="i in repeater(myRange)"></div>

1

Questa è la risposta migliorata di jzm (non posso commentare altrimenti commenterei la sua risposta perché includeva errori). La funzione ha un valore di intervallo inizio / fine, quindi è più flessibile e ... funziona. Questo caso particolare riguarda il giorno del mese:

$scope.rangeCreator = function (minVal, maxVal) {
    var arr = [];
   for (var i = minVal; i <= maxVal; i++) {
      arr.push(i);
   }
   return arr;
};


<div class="col-sm-1">
    <select ng-model="monthDays">
        <option ng-repeat="day in rangeCreator(1,31)">{{day}}</option>
    </select>
</div>

0

L'ho montato e ho visto che potrebbe essere utile per alcuni. (Sì, CoffeeScript. Sue me.)

Direttiva

app.directive 'times', ->
  link: (scope, element, attrs) ->
    repeater = element.html()
    scope.$watch attrs.times, (value) ->
      element.html ''
      return unless value?
      element.html Array(value + 1).join(repeater)

Usare:

HTML

<div times="customer.conversations_count">
  <i class="icon-picture></i>
</div>

Questo può essere più semplice?

Sono diffidente nei confronti dei filtri perché ad Angular piace rivalutarli senza motivo, ed è un enorme collo di bottiglia se ne hai migliaia come me.

Questa direttiva controllerà anche le modifiche nel tuo modello e aggiornerà l'elemento di conseguenza.


Questo è carino, ma ngRepeat mantiene il proprio ambito. Quindi dovrai eseguire la compilazione per ogni elemento aggiunto. Dovrai anche emulare le animazioni poiché ngRepeat lo fa per te.
Matsko il

2
Grazie per il contributo, ma supponendo che l'OP conosca coffeescript, di cosa si tratta, come compilarlo di nuovo in JS, o che abbia mai usato strumenti di costruzione del genere è un enorme sforzo. Siamo tutti qui per imparare o aiutare, quindi, fai il possibile, converti quel cucciolo. (Sei stato citato in giudizio!)
Augie Gardner,

0
<div ng-init="avatars = [{id : 0}]; flag = true ">
  <div ng-repeat='data in avatars' ng-if="avatars.length < 10 || flag"
       ng-init="avatars.length != 10 ? avatars.push({id : $index+1}) : ''; flag = avatars.length <= 10 ? true : false">
    <img ng-src="http://actual-names.com/wp-content/uploads/2016/01/sanskrit-baby-girl-names-400x275.jpg">
  </div>
</div>

Se vuoi raggiungere questo obiettivo in html senza alcun controller o fabbrica.


0

Supponiamo che $scope.refernceurlsia un array quindi

for(var i=0; i<$scope.refernceurl.length; i++){
    $scope.urls+=$scope.refernceurl[i].link+",";
}

-8

Questa è la variante più semplice: basta usare l'array di numeri interi ....

 <li ng-repeat="n in [1,2,3,4,5]">test {{n}}</li>


3
Questo è orribile.
Tiffany Lowe,

@Stefan, è probabile che tu stia ricevendo downgrade perché la soluzione non può utilizzare raccolte hardcoded.
Tass,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.