AngularJS For Loop mit Zahlen und Bereichen

252

Angular bietet eine gewisse Unterstützung für eine for-Schleife, die Zahlen in seinen HTML-Anweisungen verwendet:

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

Wenn Ihre Bereichsvariable jedoch einen Bereich mit einer dynamischen Nummer enthält, müssen Sie jedes Mal ein leeres Array erstellen.

In der Steuerung

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

Im HTML

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

Dies funktioniert, ist jedoch nicht erforderlich, da das Bereichsarray in der Schleife überhaupt nicht verwendet wird. Weiß jemand, wie man einen Bereich oder einen regulären Wert für den Min / Max-Wert einstellt?

Etwas wie:

<div data-ng-repeat="i in 1 .. 100">
  do something
</div>
Matsko
quelle
2
Hier noch ein paar Infos dazu. yearofmoo.com/2012/10/…
Matsko

Antworten:

281

Ich habe diese Antwort ein wenig optimiert und mir diese Geige ausgedacht .

Filter definiert als:

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

Mit der Wiederholung wie folgt verwendet:

<div ng-repeat="n in [] | range:100">
  do something
</div>
Gloopy
quelle
Interessant Ich sehe keinen Fehler in der Geige mit Chrome. Welcher Browser?
Gloopy
5
Schrecklich! ;) Ein Filter ist nicht der richtige Weg, dies zu tun. Es sollte ein neues Attribut sein, das mit zwei Werten arbeitet. Der aktuelle Index und die Obergrenze.
Ian Warburton
10
@IanWarburton Können Sie eine Antwort finden, die Ihren Kriterien entspricht?
Tau
1
@ IanWarburton: Es gibt eine Antwort von Уmed unten, die mit einer Direktive funktioniert. Du kannst sie nicht zum Laufen bringen.
Andresch Serj
1
Ich brauchte einen Bereich zwischen A und B, also habe ich diese Antwort getwittert. Jsfiddle.net/h9nLc8mk
Marcio
150

Ich habe mir eine noch einfachere Version ausgedacht, um einen Bereich zwischen zwei definierten Zahlen zu erstellen, z. 5 bis 15

Siehe Demo zu 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;
};
sqren
quelle
14
Auf solche Dinge muss man achten. Die Bereichsfunktion wird für jedes Element in der Liste mehrmals aufgerufen. Sie können böse Speicherlecks bekommen und Sie generieren viele Funktionsaufrufe. Es scheint fast einfacher zu sein, die Sammlung in den Controller zu legen.
Lucas Holt
1
var a; void 0 === a"wirklich" undefiniert.
andlrc
1
Sie können den Perf-Treffer reduzieren, indem Sie die Ergebnisse über das Memoizer-Muster zwischenspeichern. Ich bin mir nicht sicher, wie hoch die Speicherkosten sind, aber es ist eine Verbesserung. en.wikipedia.org/wiki/Memoization .
Joshua
1
@LucasHolt Endlich habe ich dieses Beispiel aktualisiert. Ich habe eine optimierte Version hinzugefügt. Es wird immer noch viele Funktionsaufrufe geben, aber das erste Ergebnis wird wiederverwendet, wodurch es viel performanter wird.
sqren
93

Nichts als einfaches Javascript (Sie brauchen nicht einmal einen Controller):

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

Sehr nützlich beim Modellieren

Maël Nison
quelle
Funktioniert nicht in Angular> 1.2.1: Ich habe diesen Fehler in der Konsole Referencing "constructor" field in Angular expressions is disallowed! Expression: [].constructor(10). Vielleicht hat das in einer früheren Version von Angular funktioniert oder ich mache etwas falsch.
AWolf
Ich denke, ich habe dies auf 1.3 oder 1.4 getestet und es war in Ordnung. Ich glaube, sie haben den Parser verbessert, so dass nicht jeder Konstruktorzugriff abgelehnt wird, sondern nur die wirklich gefährlichen (z. B. [].slice.constructorZugriff auf FunctionCodeauswertung).
Maël Nison
OK danke. Ich habe es mit 1.2.1 getestet und es hat nicht funktioniert (die in jsFiddle Dropdown enthaltene Version). Aber mit 1.3.15 funktioniert es. Siehe diese jsFiddle .
AWolf
Sehr nützlich für die Paginierung. Danke;)
Fremder
69

Ich habe mir eine etwas andere Syntax ausgedacht, die mir etwas besser passt und auch eine optionale Untergrenze hinzufügt:

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

die Sie als verwenden können

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

oder

<div ng-repeat="n in [20, 29] | makeRange">Do something 20..29: {{n}}</div>
Mormegil
quelle
Das ist großartig, aber wie können Sie alle $digestIterationen umgehen, wenn Sie einen Wert mit Gültigkeitsbereich verwenden, dh : ng-repeat="n in [1, maxValue] | makeRange"?
pspahn
Die ein und zwei Parameterfälle behandeln highBound unterschiedlich, es sollte konsistent sein
Vajk Hermecz
31

Für diejenigen, die neu in Angularjs sind. Der Index kann mit $ index abgerufen werden.

Beispielsweise:

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

Wenn Sie den praktischen Filter von Gloopy verwenden, drucken Sie: Machen
Sie etwas Nummer 0
Tun Sie etwas Nummer 1
Tun Sie etwas Nummer 2
Tun Sie etwas Nummer 3
Tun Sie etwas Nummer 4
Tun Sie etwas Nummer 5
Tun Sie etwas Nummer 6
Tun Sie etwas Nummer 7
Tun Sie etwas Nummer 8
mach etwas Nummer 9

Arnoud Sietsema
quelle
7
Stimmt, aber in diesem Fall do something number {{n}}würde auch ausreichen.
Captncraig
2
Wenn ich versuche, diesen Code in Chrome auszuführen, wird in der Konsole ein Fehler angezeigt: Fehler: [$ injor: unpr] Errors.angularjs.org/1.2.6/$injector/… ... ... at Wa.statements ( ajax.googleapis.com/ajax/libs/angularjs/1.2.6/… ) <! - ngRepeat: n in [] | Bereich: 10 -> (Leider ist der gesamte Fehler zu lang, um in die zulässige Kommentarlänge zu passen, so dass ich gerade die erste und letzte Zeile kopiert habe)
Kmeixner
1
Ich habe ein Plunker-Beispiel für den Code erstellt, damit Sie ihn mit Ihrem Code vergleichen können. plnkr.co/edit/tN0156hRfX0M6k9peQ2C?p=preview
Arnoud Sietsema
21

Eine kurze Möglichkeit hierfür wäre die Verwendung der _.range () -Methode von 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>
Michael J. Calkins
quelle
1
@jwoodward Er hat nie gesagt, dass das keine Option ist. Meine Lösung ist bei weitem die einfachste und am meisten getestete, dank Unit-Tests von ihrem Repo. Sie können das js jederzeit aus der nicht abgeschlossenen Bibliothek entfernen und als Funktion einbinden.
Michael J. Calkins
4
Das hat er zwar nie gesagt. Im Allgemeinen ist es jedoch eine schlechte Idee, ein Problem in einer Bibliothek durch Anwenden einer anderen Bibliothek zu lösen. Es verhindert lediglich, dass Sie lernen, wie die erste Bibliothek richtig verwendet wird. Wenden Sie sich an eine andere Bibliothek, wenn die aktuelle keine gute Lösung enthält.
Erik Honn
5
Ich benutze bereits überall lodash, dies war bei weitem die einfachste Lösung. Danke dir. Ich habe gerade $ scope.range = _.range gemacht, dann ist es einfach in jeder Vorlage mit dynamischen Start- / Endwerten zu verwenden.
j_walker_dev
2
@ErikHonn: UnderscoreJS löst ein völlig anderes Problem als AngularJS. Es gibt keine gute Lösung zum Generieren von Bereichen in AngularJS, da dies nicht der Zweck der Bibliothek ist.
AlexFoxGill
2
Dies ist alt, aber sicherlich ist die Verwendung einer Bibliothek, die genau dafür ausgelegt ist, einen Bereich zu erstellen, anstatt eine Funktion in Ihrer aktuellen Bibliothek nicht semantisch zu missbrauchen, ein weitaus besserer Weg? Sicher, Sie können etwas lernen, aber am Ende haben Sie verzerrte Verwendungen von Dingen, die für etwas anderes entwickelt wurden.
Dan
20

Ich benutze meine benutzerdefinierte ng-repeat-rangeDirektive:

/**
 * 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);
        }
    };
}]);

und HTML-Code ist

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

oder einfach

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

oder auch einfach

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

oder nur

<div ng-repeat-range="7">
    Hello 7 times!
</div>
Pleerock
quelle
1
Theoretisch schön, aber die Injektion von element.attr('ng-repeat', 'n in [' + rangeString + ']');funktioniert nicht ...
Stefan Walther
"Ich benutze...". Haben Sie tatsächlich versucht, es zu verwenden? Das Attribut ng-repeat wird nicht kompiliert.
Peter Hedberg
Danke Peter, ich habe den Code aktualisiert. Ich habe diese Direktive in der Vergangenheit verwendet, aber sie hat mein Code-Repository verlassen
Pleerock
9

Am einfachsten war es keine Codelösung, ein Array mit dem Bereich zu initiieren und den $ index + zu verwenden, wie viel ich auch versetzen möchte:

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

Methodendefinition

Der folgende Code definiert eine Methode, range()die für den gesamten Anwendungsbereich verfügbar ist MyApp. Sein Verhalten ist der Python- range()Methode sehr ähnlich .

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

Verwendung

Mit einem Parameter:

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

0, 1, 2,

Mit zwei Parametern:

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

1, 2, 3, 4,

Mit drei Parametern:

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

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

Mathieu Rodic
quelle
6

Sie können 'after'- oder' before'-Filter im Modul angle.filter verwenden ( 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>

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

a8m
quelle
6

Ohne Änderungen an Ihrem Controller können Sie Folgendes verwenden:

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

Genießen!

odroz
quelle
Ich habe mehr als einen Tag gekämpft und schließlich hat nur diese Syntax für mich funktioniert
Agnel Amodia
3

Kürzeste Antwort: 2 Codezeilen

JS (in Ihrem AngularJS-Controller)

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

... wo myCountist die Anzahl der Sterne, die an dieser Stelle erscheinen sollen?

Sie können $indexfür alle Verfolgungsvorgänge verwenden. Wenn Sie beispielsweise eine Mutation auf den Index drucken möchten, können Sie Folgendes in das Feld einfügen div:

{{ ($index + 1) * 0.5 }}
JellicleCat
quelle
2

Verwenden von UnderscoreJS:

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

Wenn Sie dies anwenden, $rootScopewird es überall verfügbar:

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

Sehr einfach:

$scope.totalPages = new Array(10);

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

Hallo, Sie können dies mit reinem HTML mit AngularJS erreichen (KEINE Richtlinie ist erforderlich!)

<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>
Pavan Kosanam
quelle
1

Stellen Sie den Bereich im Controller ein

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

Setzen Sie Wiederholung in HTML-Vorlagendatei

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

Eine Verbesserung der Lösung von @ 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;
  };
});

Verwendung

<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

deriberale Surfer
quelle
1

Ich habe folgendes versucht und es hat gut funktioniert für mich:

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

Winkel 1.3.6

Araghorn
quelle
1

Spät zur Party. Aber am Ende habe ich nur folgendes gemacht:

In Ihrem 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>
mnsr
quelle
1

Dies ist die verbesserte Antwort von jzm (ich kann nicht kommentieren, sonst würde ich ihre / seine Antwort kommentieren, weil er / sie Fehler enthielt). Die Funktion hat einen Start- / Endbereichswert, ist also flexibler und ... funktioniert. Dieser besondere Fall gilt für den Tag des Monats:

$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>
Fresko
quelle
0

Ich habe das ausgepeitscht und gesehen, dass es für einige nützlich sein könnte. (Ja, CoffeeScript. Verklage mich.)

Richtlinie

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)

Benutzen:

HTML

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

Kann das einfacher werden?

Ich bin vorsichtig mit Filtern, weil Angular sie immer wieder ohne guten Grund neu bewertet, und es ist ein großer Engpass, wenn Sie Tausende von Filtern haben, wie ich.

Diese Anweisung überwacht sogar Änderungen in Ihrem Modell und aktualisiert das Element entsprechend.

Prathan Thananart
quelle
Das ist schön, aber ngRepeat behält seinen eigenen Umfang bei. Sie müssen also die Kompilierung für jedes hinzugefügte Element ausführen. Sie müssen auch Animationen emulieren, da ngRepeat dies für Sie erledigt.
Matsko
2
Vielen Dank für Ihren Beitrag, aber vorausgesetzt, das OP kennt Coffeescript, was es ist, wie man es wieder in JS kompiliert oder hat jemals solche Build-Tools verwendet, ist eine große Herausforderung. Wir sind alle hier, um zu lernen oder zu helfen. Gehen Sie also noch einen Schritt weiter und bekehren Sie diesen Welpen. (Sie wurden verklagt!)
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>

Wenn Sie dies in HTML ohne Controller oder Factory erreichen möchten.

Virendra Singh Rathore
quelle
0

Angenommen, es $scope.refernceurlhandelt sich dann um ein Array

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

Dies ist die einfachste Variante: Verwenden Sie einfach ein Array von Ganzzahlen ....

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

Stefan
quelle
3
Das ist schrecklich.
Tiffany Lowe
@Stefan, Sie erhalten wahrscheinlich Downvotes, da die Lösung keine fest codierten Sammlungen verwenden kann.
Tass