AngularJS для цикла с числами и диапазонами

Angular предоставляет некоторую поддержку цикла for с использованием чисел в своих директивах HTML:

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

person matsko    schedule 08.08.2012    source источник
comment
Вот еще немного информации об этом. yearofmoo. ru / 2012/10 /   -  person matsko    schedule 26.10.2012


Ответы (24)


Я немного изменил этот ответ и получил эта скрипка.

Фильтр определяется как:

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>
person Gloopy    schedule 09.08.2012
comment
Интересно, что я не вижу ошибки в скрипте при использовании Chrome. Какой браузер? - person Gloopy; 14.05.2013
comment
Ужасно! ;) Фильтр не подходит для этого. Это должен быть новый атрибут, работающий с двумя значениями. Текущий индекс и верхняя граница. - person Ian Warburton; 19.05.2013
comment
@IanWarburton Можете ли вы придумать ответ, который соответствует вашим критериям? - person dewd; 27.05.2013
comment
Боюсь, что сейчас нет. Я недостаточно хорошо это знаю. Но когда я это сделаю, я вернусь и добавлю еще один! - person Ian Warburton; 27.05.2013
comment
мог сделать ‹div ng-repeat = n в myDynamicVar | диапазон ›что-то ‹/div› У меня есть что-то вроде этого рабочего p в pagesummary.totalPages | пагинатор - person skipy; 01.07.2013
comment
@IanWarburton: Ниже есть ответ от Умеда, который работает с директивой, я не могу заставить его работать. - person Andresch Serj; 04.03.2014
comment
Мне нужен был диапазон от A до B, поэтому я настроил этот ответ jsfiddle.net/h9nLc8mk - person Marcio; 19.04.2015
comment
Разве мы не можем сделать то же самое без массива? использование массива для больших значений кажется мне неправильным ... можем ли мы использовать какую-то функцию генератора? - person pravin; 16.02.2016
comment
@Gloopy Как получить результат типа do something + index? - person Mohammad Kermani; 03.08.2016

Я придумал еще более простую версию для создания диапазона между двумя определенными числами, например. От 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;
};
person sqren    schedule 15.06.2013
comment
Вы должны остерегаться подобных вещей. Функция диапазона будет вызываться несколько раз для каждого элемента в списке. Вы можете получить неприятные утечки памяти и генерировать много вызовов функций. Кажется, что поместить коллекцию в контроллер проще. - person Lucas Holt; 18.06.2013
comment
var a; void 0 === a действительно неопределенный. - person andlrc; 19.08.2014
comment
Вы можете уменьшить производительность, кэшируя результаты с помощью шаблона памятки. Не уверен, сколько стоит память, но это улучшение. en.wikipedia.org/wiki/Memoization. - person Joshua; 04.02.2015
comment
@LucasHolt Наконец-то добрался до обновления этого примера. Я добавил оптимизированную версию. У него по-прежнему будет много вызовов функций, но он будет повторно использовать первый результат, что сделает его гораздо более производительным. - person sqren; 14.11.2015

Ничего, кроме простого Javascript (вам даже не нужен контроллер):

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

Очень полезно при макетировании

person Maël Nison    schedule 26.02.2015
comment
Не работает в Angular ›1.2.1: У меня эта ошибка в консоли Referencing "constructor" field in Angular expressions is disallowed! Expression: [].constructor(10). Возможно, это работало в предыдущей версии Angular, или я что-то делаю не так. - person AWolf; 04.04.2015
comment
Думаю, я тестировал это на 1.3 или 1.4, и все было нормально. Я считаю, что они улучшили синтаксический анализатор, поэтому он не отклоняет доступ к каждому «конструктору», а только к действительно опасным (например, [].slice.constructor, который дает доступ к Function, следовательно, к оценке кода). - person Maël Nison; 04.04.2015
comment
Хорошо спасибо. Я тестировал его с помощью 1.2.1, и он не работал (версия включена в раскрывающийся список jsFiddle). Но с 1.3.15 работает. См. Этот jsFiddle. - person AWolf; 04.04.2015
comment
Очень полезно для нумерации страниц. Спасибо ;) - person Stranger; 29.03.2016

Я придумал немного другой синтаксис, который мне немного больше подходит и также добавляет необязательную нижнюю границу:

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>

or

<div ng-repeat="n in [20, 29] | makeRange">Do something 20..29: {{n}}</div>
person Mormegil    schedule 18.02.2013
comment
Это здорово, но как обойти все $digest итерации при использовании ограниченного значения, например: ng-repeat="n in [1, maxValue] | makeRange"? - person pspahn; 01.07.2015
comment
Случаи с одним и двумя параметрами трактуют highBound по-разному, они должны быть последовательными. - person Vajk Hermecz; 29.09.2016

Для тех, кто плохо знаком с 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

person Arnoud Sietsema    schedule 04.02.2013
comment
Верно, но в этом случае do something number {{n}} тоже будет достаточно. - person captncraig; 28.11.2013
comment
Когда я пытаюсь запустить этот код в Chrome, я получаю сообщение об ошибке в консоли: Ошибка: [$ injector: unpr] errors.angularjs.org/1.2.6/$injector/ ... ... в Wa.statements (ajax.googleapis.com/ajax/libs/angularjs/1.2 .6 /) ‹! - ngRepeat: n in [] | диапазон: 10 - ›(К сожалению, вся ошибка слишком длинна, чтобы уместиться в разрешенной длине комментария, поэтому я просто скопировал первую и последнюю строку) - person Kmeixner; 31.12.2013
comment
Я создал пример кода Plunker, чтобы вы могли сравнить его со своим кодом. plnkr.co/edit/tN0156hRfX0M6k9peQ2C?p=preview - person Arnoud Sietsema; 04.01.2014

Короткий способ сделать это - использовать метод _.range () в 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>
person Michael J. Calkins    schedule 26.09.2013
comment
@jwoodward Он никогда не говорил, что это не вариант. Мое решение на сегодняшний день является самым простым и проверенным благодаря модульному тестированию из их репо. Вы всегда можете взять js из неминифицированной библиотеки и включить его как функцию. - person Michael J. Calkins; 22.11.2013
comment
Правда, он никогда этого не говорил. Но, как правило, решение проблемы в одной библиотеке путем применения другой библиотеки - плохая идея, это просто мешает вам узнать, как правильно использовать первую библиотеку. Обратиться к другой библиотеке, когда / если в текущей нет хорошего решения. - person Erik Honn; 04.12.2013
comment
Я уже везде использую lodash, это было самым простым решением. Спасибо. Я только что сделал $ scope.range = _.range, после чего его легко использовать в любом шаблоне с динамическими начальными / конечными значениями. - person j_walker_dev; 08.05.2014
comment
@ErikHonn: UnderscoreJS решает совершенно другую проблему, чем AngularJS. Нет хорошего решения для генерации диапазонов в AngularJS, потому что это не цель библиотеки. - person AlexFoxGill; 24.06.2014
comment
За исключением того, что для этого есть решение, вы пишете специальную директиву или очень простой фильтр. Вот почему вам следует избегать решения проблем, применяя другую библиотеку, это мешает вам учиться. Это не значит, что другие библиотеки нельзя использовать, но вы всегда должны пытаться решить эту проблему без предварительного уведомления. Конечно, если у вас уже есть подчеркивание по другим причинам, продолжайте, но все же хорошо изучить настоящий способ: P - person Erik Honn; 24.06.2014
comment
Это устарело, но, конечно же, использование библиотеки, предназначенной для таких вещей, как создание диапазона, вместо того, чтобы злоупотреблять функцией в вашей текущей библиотеке несемантическим способом, - это гораздо лучший способ? Конечно, вы можете чему-то научиться, но в конечном итоге вы получите искаженное использование вещей, предназначенных для чего-то другого. - person Dan; 08.05.2016

Я использую свою собственную директиву 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>
person pleerock    schedule 29.01.2014
comment
Теоретически неплохо, но закачка element.attr('ng-repeat', 'n in [' + rangeString + ']'); не работает ... - person Stefan Walther; 24.06.2014
comment
Я использую .... Вы вообще пробовали его использовать? Атрибут ng-repeat не компилируется. - person Peter Hedberg; 29.09.2014
comment
Спасибо, Питер, Айв обновил код. Я использовал эту директиву в прошлом, но она все равно покинула мой репозиторий кода - person pleerock; 30.09.2014

Самым простым решением без кода было инициировать массив с диапазоном и использовать $ index +, сколько бы я ни хотел компенсировать:

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

Определение метода

В приведенном ниже коде определяется метод range(), доступный для всей области MyApp вашего приложения. Его поведение очень похоже на метод range() в 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;
    };
}]);

использование

С одним параметром:

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

person Mathieu Rodic    schedule 10.12.2014

Вы можете использовать фильтры «после» или «до» в модуле 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>

результат: 5, 6, 7, 8, 9, 10

person a8m    schedule 17.07.2014

Без каких-либо изменений в вашем контроллере вы можете использовать это:

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

Наслаждаться!

person odroz    schedule 22.05.2016
comment
боролись больше суток, и, наконец, у меня сработал только этот синтаксис - person Agnel Amodia; 24.07.2018

Кратчайший ответ: 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 }}
person JellicleCat    schedule 10.12.2014

Привет, вы можете добиться этого, используя чистый html, используя AngularJS (директива НЕ требуется!)

<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>
person Pavan Kosanam    schedule 02.08.2016

Использование UnderscoreJS:

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

Применение этого к $rootScope делает его доступным повсюду:

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

Очень простой:

$scope.totalPages = new Array(10);

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

Установить область действия в контроллере

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>
person Ahmer    schedule 11.09.2014

Улучшение решения @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

person theliberalsurfer    schedule 29.11.2014

Я попробовал следующее, и у меня это сработало:

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

Угловой 1.3.6

person araghorn    schedule 09.04.2015

Поздно на вечеринку. Но в итоге я просто сделал это:

В вашем контроллере:

$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>
person mnsr    schedule 15.12.2015

Это улучшенный ответ 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>
person fresko    schedule 09.03.2016

<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 без какого-либо контроллера или фабрики.

person Virendra Singh Rathore    schedule 27.06.2016

Я придумал это и увидел, что некоторым это может быть полезно. (Да, 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 любит все время переоценивать их без уважительной причины, и это огромное узкое место, если у вас их тысячи, как у меня.

Эта директива даже будет следить за изменениями в вашей модели и соответствующим образом обновлять элемент.

person Prathan Thananart    schedule 27.06.2013
comment
Это хорошо, но ngRepeat поддерживает собственную область видимости. Поэтому вам придется запускать компиляцию для каждого добавленного элемента. Вам также необходимо эмулировать анимацию, поскольку ngRepeat делает это за вас. - person matsko; 27.06.2013
comment
Спасибо за участие, но если предположить, что OP знает coffeescript, что это такое, как скомпилировать его обратно в JS, или когда-либо использовал какие-либо инструменты сборки, подобные этому, - огромная натяжка. Мы все здесь, чтобы учиться или помогать, так что сделайте все возможное, преобразовав этого щенка. (На вас подали в суд!) - person Augie Gardner; 11.07.2014

Предположим, что $scope.refernceurl - это массив, тогда

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

Это самый простой вариант: использовать массив целых чисел ....

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

person Stefan    schedule 05.06.2015
comment
Это ужасно. - person Tiffany Lowe; 09.11.2016
comment
@Stefan, вы, вероятно, получаете отрицательные голоса, потому что решение не может использовать жестко запрограммированные коллекции. - person Tass; 21.12.2016