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.