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>

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>

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

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


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>

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


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>

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>

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>

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,


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


6

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

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

Genießen!


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

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>

2

Sehr einfach:

$scope.totalPages = new Array(10);

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

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>

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>

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


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


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>

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>

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.


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.


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+",";
}

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


3
Das ist schrecklich.
Tiffany Lowe

@Stefan, Sie erhalten wahrscheinlich Downvotes, da die Lösung keine fest codierten Sammlungen verwenden kann.
Tass
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.