带数字和范围的AngularJS For循环


252

Angular确实在其HTML指令中使用数字为for循环提供了一些支持:

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

但是,如果您的范围变量包含具有动态数字的范围,则您每次都需要创建一个空数组。

在控制器中

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

在HTML中

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

这行得通,但是没有必要,因为我们根本不会在循环中使用范围数组。有谁知道设置最小值/最大值的范围或常规值?

就像是:

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

2
这是有关此的更多信息。yearofmoo.com/2012/10/...
matsko

Answers:


280

我稍微调整了这个答案,想出了这个小提琴

过滤器定义为:

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

重复使用如下:

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

有趣的是,我没有看到使用Chrome的小提琴出现错误。哪个浏览器?
Gloopy

5
恐怖!;)过滤器不是这样做的方法。它应该是一个可以使用两个值的新属性。当前索引和上限。
伊恩·沃伯顿

10
@IanWarburton您能提出符合您条件的答案吗?
2013年

1
@IanWarburton:Уmed下面有一个与指令一起使用的答案,您无法使用它。
Andresch Serj 2014年

1
我需要一个介于A和B之间的范围,所以我将这个答案周六了jsfiddle.net/h9nLc8mk
Marcio

150

我想出了一个更简单的版本,用于在两个定义的数字之间创建范围,例如。5至15

参见有关JSFiddle的演示

HTML

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

控制器

$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
您必须提防这种事情。对于列表中的每个项目,都会多次调用range函数。您可能会收到令人讨厌的内存泄漏,并且正在生成许多函数调用。将集合放入控制器内部似乎比较容易。
Lucas Holt

1
var a; void 0 === a“真正”未定义。
andlrc

1
您可以通过备忘录模式将结果缓存起来,从而降低性能表现。不知道内存成本是多少,但这是一种改进。en.wikipedia.org/wiki/备忘录
2015年

1
@LucasHolt终于解决了这个示例。我添加了优化版本。它仍将有许多函数调用,但它将重用第一个结果,从而使其性能更高。
sqren 2015年

93

只是简单的Javascript(您甚至不需要控制器):

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

样机制作时非常有用


无法在Angular> 1.2.1中工作:在控制台中出现此错误Referencing "constructor" field in Angular expressions is disallowed! Expression: [].constructor(10)。可能是在Angular的早期版本中起作用,或者我做错了什么。
2015年

我想我在1.3或1.4上进行了测试,这很好。我相信他们已经改进了解析器,因此它不会拒绝所有“构造函数”访问,而只会拒绝真正危险的[].slice.constructor访问(例如,它可以访问Function,因此可以进行代码评估)。
尼尔·尼森

好,谢谢。我用1.2.1对其进行了测试,但无法正常工作(jsFiddle下拉列表中包含的版本)。但是使用1.3.15可以正常工作。看到这个jsFiddle
2015年

对分页很有用。谢谢;)
陌生人

69

我想出了一个稍有不同的语法,它更适合我,并且还添加了一个可选的下限:

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

您可以将其用作

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

要么

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

很好,但是$digest当使用有作用域的值(即:)时,如何解决所有迭代问题ng-repeat="n in [1, maxValue] | makeRange"
pspahn 2015年

一和两个param案例对highBound的处理方式不同,应该保持一致
Vajk Hermecz

31

对于angularjs的新手。可以使用$ index获得索引。

例如:

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

当您使用Gloopy的便捷过滤器时,将打印:
做数字0
做某事1
做某事2
做某事3
做某事4
做某事5
做某事6
做某事7
做某事8做某事
做9号


7
是的,但是在这种情况下do something number {{n}}也足够了。
captncraig 2013年

2
当我尝试运行在Chrome我这段代码在控制台得到一个错误:错误:[$注射器:unpr] errors.angularjs.org/1.2.6/$injector/... ......在Wa.statements(ajax.googleapis.com/ajax/libs/angularjs/1.2.6/…)<!-ngRepeat:[]中的n | 范围:10->(不幸的是,整个错误太长,无法容纳允许的注释长度,因此我只复制了第一行和最后一行)
Kmeixner 2013年

1
我创建了一个代码示例,以便您可以将其与您的代码进行比较。plnkr.co/edit/tN0156hRfX0M6k9peQ2C?p=preview
Arnoud Sietsema 2014年

21

一种简单的方法是使用Underscore.js的_.range()方法。:)

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他从未说过这不是一个选择。到目前为止,我的解决方案是最简单,经过最多测试的,这要归功于其仓库中的单元测试。您始终可以将js从未缩小的库中取出,并将其作为一个函数包含在内。
Michael J. Calkins

4
没错,他从未这么说。但是,通过应用另一个库来解决一个库中的问题通常是一个坏主意,它只是阻止您学习如何正确使用第一个库。如果当前库中没有好的解决方案,请转到另一个库。
Erik Honn

5
我已经在各处使用lodash,这是迄今为止最简单的解决方案。谢谢。我只是做了$ scope.range = _.range,然后它易于在具有动态起始/结束值的任何模板中使用。
j_walker_dev 2014年

2
@ErikHonn:UnderscoreJS解决了与AngularJS完全不同的问题。在AngularJS中没有很好的生成范围的解决方案,因为那不是库的目的。
AlexFoxGill 2014年

2
这已经很老了,但是一定要使用一个库来设计与创建范围完全一样的事情,而不是以非语义的方式滥用当前库中的功能,这是更好的方法吗?当然,您可能会学到一些东西,但最终会误用为其他目的设计的东西。

20

我使用我的自定义ng-repeat-range指令:

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

和html代码是

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

或简单地

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

甚至简单地

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

要不就

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

1
理论上不错,但是注入element.attr('ng-repeat', 'n in [' + rangeString + ']');不起作用...
Stefan Walther

“我用...”。您实际上尝试过使用它吗?ng-repeat属性将不会被编译。
彼得·赫德伯格

谢谢彼得,我已经更新了代码。我过去使用过此指令,但它仍然离开了我的代码存储库
pleerock 2014年

9

最简单的无代码解决方案是使用范围初始化数组,并使用$ index +,但我想通过以下方式抵消:

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

7

方法定义

下面的代码定义了range()可用于整个应用程序范围的方法MyApp。它的行为与Python range()方法非常相似。

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

用法

有一个参数:

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

0, 1, 2,

有两个参数:

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

1, 2, 3, 4,

具有三个参数:

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

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


6

您可以在angular.filter模块(https://github.com/a8m/angular-filter)中使用'after'或'before'过滤器

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

HTML:

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

结果: 5、6、7、8、9、10


6

无需对控制器进行任何更改,您可以使用以下命令:

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

请享用!


苦苦挣扎了一天多,终于只有这种语法对我
有用

3

最短答案:2行代码

JS(在您的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>

... myCount在此位置应出现的星数。

您可以使用$index任何跟踪操作。例如,如果您想在索引上打印一些突变,则可以将以下内容放入div

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

2

使用UnderscoreJS:

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

将其应用到$rootScope任何地方都可以使用:

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

2

很简单的一个:

$scope.totalPages = new Array(10);

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

2

嗨,您可以使用AngularJS使用纯HTML来实现此目标(无需指令!)

<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

在控制器中设置范围

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

在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

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

用法

<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

我尝试了以下方法,对我来说效果很好:

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

角1.3.6


1

晚会。但是我最终只是这样做:

在您的控制器中:

$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

这是jzm的改进答案(我无法发表评论,我会评论她/他的答案,因为他/他包含错误)。该函数具有开始/结束范围值,因此更加灵活,并且...有效。此特殊情况适用于每月的某天:

$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

我整理了一下,发现它可能对某些人有用。(是的,CoffeeScript。起诉我。)

指示

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)

使用方法:

的HTML

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

可以更简单吗?

我对过滤器保持警惕,因为Angular总是无缘无故地喜欢重新评估它们,而如果像我一样拥有成千上万的过滤器,这将是一个巨大的瓶颈。

该指令甚至会监视模型中的更改,并相应地更新元素。


这很好,但是ngRepeat保留了它自己的作用域。因此,您必须为添加的每个项目运行编译。您还需要模拟动画,因为ngRepeat会为您做到这一点。
matsko

2
感谢您的贡献,但是假设OP知道coffeescript,它是什么,如何将其编译回JS,或者曾经使用过任何这样的构建工具都是很大的工作。我们都在这里学习或帮助,所以,多加努力,转换那只小狗。(您已被起诉!)
Augie Gardner 2014年

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>

如果要在没有任何控制器或工厂的情况下用html实现此目的。



-8

这是最简单的变体:只需使用整数数组即可。

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


3
这太可怕了。
蒂芙尼·洛

@Stefan,您可能会收到不赞成票,因为该解决方案无法使用硬编码的集合。
塔斯(Tass)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.