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

217

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>

Это работает, но это не нужно, поскольку мы не будем использовать массив диапазонов вообще внутри цикла. Кто-нибудь знает о настройке диапазона или регулярного значения min/max?

Что-то вроде:

<div data-ng-repeat="i in 1 .. 100">
  do something
</div>
  • 2
    Вот еще немного информации об этом. yearofmoo.com/2012/10/...
Теги:
angularjs-ng-repeat

23 ответа

241
Лучший ответ

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

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

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>
  • 0
    Интересно, что я не вижу ошибки в скрипке с использованием Chrome. Какой браузер?
  • 5
    Ужасный! ;) Фильтр не способ сделать это. Это должен быть новый атрибут, который работает с двумя значениями. Текущий индекс и верхняя граница.
Показать ещё 7 комментариев
121

Я придумал еще более простую версию для создания диапазона между двумя определенными числами, например. 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
    Вы должны следить за такими вещами. Функция диапазона будет вызываться несколько раз для каждого элемента в списке. Вы можете получить неприятные утечки памяти, и вы генерируете много вызовов функций. Кажется, проще поместить коллекцию в контроллер.
  • 1
    var a; void 0 === a "по-настоящему" не определено.
Показать ещё 2 комментария
70

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

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

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

  • 0
    Не работает в Angular> 1.2.1: Я получил эту ошибку в консоли. Referencing "constructor" field in Angular expressions is disallowed! Expression: [].constructor(10) . Возможно, это работало в предыдущей версии Angular, или я делаю что-то не так.
  • 0
    Я думаю, что я проверял это на 1,3 или 1,4, и это было хорошо. Я считаю, что они улучшили синтаксический анализатор, поэтому он не отвергает каждый доступ «конструктора», а только действительно опасные (такие как [].slice.constructor , который предоставляет доступ к Function , следовательно, для оценки кода).
Показать ещё 2 комментария
66

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

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>
  • 0
    Это замечательно, но как обойти все итерации $digest при использовании значения в области, то есть: ng-repeat="n in [1, maxValue] | makeRange" ?
  • 0
    Я опубликовал пакет на npm / bower: github.com/Zertz/ng-range-filter
Показать ещё 2 комментария
30

Для тех, кто не знаком с угловыми. Индекс можно получить с помощью $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}} также будет достаточно.
  • 2
    Когда я пытаюсь запустить этот код в Chrome, в консоли появляется сообщение об ошибке: Ошибка: [$ injector: unpr] errors.angularjs.org/1.2.6/$injector/… ... ... at Wa.statements ( ajax.googleapis.com/ajax/libs/angularjs/1.2.6/… ) <! - ngRepeat: n in [] | диапазон: 10 -> (к сожалению, вся ошибка слишком длинная, чтобы уместиться в разрешенную длину комментария, поэтому я просто скопировал первую и последнюю строку)
Показать ещё 1 комментарий
20

Короче говоря, это будет использовать метод 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 из unminified библиотеки и включить ее в качестве функции.
  • 4
    Правда, он никогда этого не говорил. Но, как правило, плохая идея решить проблему в одной библиотеке с помощью другой библиотеки, это просто мешает вам научиться правильно использовать первую библиотеку. Обратитесь к другой библиотеке, если / если в текущем нет хорошего решения.
Показать ещё 4 комментария
18

Я использую свою собственную директиву 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 + ']'); не работает ...
  • 0
    "Я использую...". Вы на самом деле пытались его использовать? Атрибут ng-repeat не будет скомпилирован.
Показать ещё 1 комментарий
9

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

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

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

4

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

В приведенном ниже коде определяется метод 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="for i in range(3)">{{ i }}, </span>

0, 1, 2,

С двумя параметрами:

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

1, 2, 3, 4,

С тремя параметрами:

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

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

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

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

$scope.totalPages = new Array(10);

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

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

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

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

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

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

<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

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

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

Наслаждайтесь!

  • 0
    боролись больше суток и наконец у меня сработал только этот синтаксис
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>
1

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

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

Angular 1.3.6

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

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

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

0

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

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

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

Я взбил это и увидел, что это может быть полезно для некоторых. (Да, CoffeeScript. Sue me.)

Директива

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

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

  • 0
    Это хорошо, но ngRepeat поддерживает свою собственную область видимости. Так что вам придется запускать компиляцию для каждого добавленного элемента. Вам также нужно будет эмулировать анимацию, поскольку ngRepeat сделает это за вас.
  • 2
    Спасибо за помощь, но если предположить, что OP знает coffeescript, что это такое, как его скомпилировать обратно в JS, или когда-либо использовал какие-либо инструменты для сборки, подобные этому, это очень сложно. Мы все здесь, чтобы учиться или помогать, так что сделайте все возможное, превратите этого щенка. (Вам предъявили иск!)
-5

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

 <li ng-repeat="n in [1,2,3,4,5]">test {{n}}</li>
  • 3
    Это ужасно
  • 0
    @ Стефан, вы, вероятно, получаете отрицательные отзывы, потому что решение не может использовать жестко закодированные коллекции.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню