AngularJS For Loop with Numbers & Ranges

2018-12-31 15:26发布

问题:

Angular does provide some support for a for loop using numbers within its HTML directives:

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

But if your scope variable includes a range that has a dynamic number then you will need to create an empty array each time.

In the controller

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

In the HTML

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

This works, but it is unnecessary since we won\'t be using the range array at all within the loop. Does anyone know of setting a range or a regular for min/max value?

Something like:

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

回答1:

I tweaked this answer a bit and came up with this fiddle.

Filter defined as:

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

With the repeat used like this:

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


回答2:

I came up with an even simpler version, for creating a range between two defined numbers, eg. 5 to 15

See demo on 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;
};


回答3:

Nothing but plain Javascript (you don\'t even need a controller):

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

Very useful when mockuping



回答4:

I came up with a slightly different syntax which suits me a little bit more and adds an optional lower bound as well:

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

which you can use as

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

or

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


回答5:

For those new to angularjs. The index can be gotten by using $index.

For example:

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

Which will, when you\'re using Gloopy\'s handy filter, print:
do something number 0
do something number 1
do something number 2
do something number 3
do something number 4
do something number 5
do something number 6
do something number 7
do something number 8
do something number 9



回答6:

A short way of doing this would be to use Underscore.js\'s _.range() method. :)

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>


回答7:

I use my custom ng-repeat-range directive:

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

and html code is

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

or simply

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

or even simply

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

or just

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


回答8:

Simplest no code solution was to init an array with the range, and use the $index + however much I want to offset by:

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


回答9:

You can use \'after\' or \'before\' filters in angular.filter module (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>

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



回答10:

Method definition

The code below defines a method range() available to the entire scope of your application MyApp. Its behaviour is very similar to the Python range() method.

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

Usage

With one parameter:

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

0, 1, 2,

With two parameters:

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

1, 2, 3, 4,

With three parameters:

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

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



回答11:

Shortest answer: 2 lines of code

JS (in your 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>

...where myCount is the number of stars that should appear in this location.

You can use $index for any tracking operations. E.g. if you want to print some mutation on the index, you might put the following in the div:

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


回答12:

Without any change in your controller, you can use this:

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

Enjoy!



回答13:

Using UnderscoreJS:

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

Applying this to $rootScope makes it available everywhere:

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


回答14:

Very simple one:

$scope.totalPages = new Array(10);

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


回答15:

Set Scope in controller

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

Set Repeat in Html Template File

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


回答16:

An improvement to @Mormegil\'s solution

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

usage

<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



回答17:

I tried the following and it worked just fine for me:

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

Angular 1.3.6



回答18:

This is jzm\'s improved answer (i cannot comment else i would comment her/his answer because s/he included errors). The function has a start/end range value, so it\'s more flexible, and... it works. This particular case is for day of month:

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


回答19:

Hi you can achieve this using pure html using AngularJS (NO Directive is required!)

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


回答20:

I whipped this up and saw it might be useful for some. (Yes, CoffeeScript. Sue me.)

Directive

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)

To use:

HTML

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

Can this get any simpler?

I\'m wary about filters because Angular likes to re-evaluate them for no good reason all the time, and it\'s a huge bottleneck if you have thousands of them like I do.

This directive will even watch for changes in your model, and update the element accordingly.



回答21:

Late to the party. But i ended up just doing this:

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


回答22:

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

If you want to achieve this in html without any controller or factory.



回答23:

This is the simplest variant: just use array of integers....

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