AngularJS Для циклу з номерами та діапазонами


252

Angular надає певну підтримку циклу, використовуючи номери в межах своїх директив 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/…
мацько

Відповіді:


281

Я трохи переробив цю відповідь і придумав цю загадку .

Фільтр визначено як:

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 Чи можете ви знайти відповідь, яка відповідає вашим критеріям?
роса

1
@IanWarburton: Нижче є відповідь Умеда, яка працює з директивою, я не можу змусити її працювати.
Андреш Серж

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
Ви повинні стежити за такими речами. Функція діапазону буде викликана кілька разів для кожного елемента в списку. Ви можете отримати неприємні витоки пам’яті і ви генеруєте багато функціональних дзвінків. Майже простіше здати колекцію всередині контролера.
Лукас Холт

1
var a; void 0 === a"справді" невизначений.
andlrc

1
Ви можете зменшити хіт perf, кешуючи результати за допомогою шаблона мемуатора. Не впевнений, яка вартість пам'яті, але це поліпшення. en.wikipedia.org/wiki/Переміщення .
Джошуа

1
@LucasHolt Нарешті обійшов оновлення цього прикладу. Я додав оптимізовану версію. У ньому все ще буде багато функціональних викликів, але він повторно використовувати перший результат, що робить його набагато ефективнішим.
sqren

93

Нічого, крім простого Javascript (вам навіть не потрібен контролер):

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

Дуже корисний при макетування


Не працює в кутовій> 1.2.1: у мене з’явилася помилка в консолі Referencing "constructor" field in Angular expressions is disallowed! Expression: [].constructor(10). Можливо, це працювало в попередній версії Angular або я роблю щось не так.
AWolf

Думаю, я тестував це на 1.3 або 1.4, і це було чудово. Я вважаю, що вони вдосконалили аналізатор, тому він не відкидає доступ кожного "конструктора", а лише дійсно небезпечні (наприклад [].slice.constructor, що дає доступ Function, отже, і до кодової оцінки).
Maël Nison

Добре, дякую. Я перевірив його з 1.2.1, і він не працював (версія, що входить у спадне меню jsFiddle). Але з 1.3.15 він працює. Дивіться цей jsFiddle .
AWolf

Прекрасно корисний для пагинації. Дякую;)
Незнайомець

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

Один і два випадки парами трактуються з високим зв’язком по-різному, воно повинно бути послідовним
Вайк Гермеч

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

2
Коли я намагаюся запустити цей код у Chrome, у консолі з’являється помилка: Помилка: [$ injector: unpr] errors.angularjs.org/1.2.6/$injector/… ... ... у Wa.statements ( ajax.googleapis.com/ajax/libs/angularjs/1.2.6/… ) <! - ngПовторити: n у [] | діапазон: 10 -> (На жаль, вся помилка занадто довга, щоб вписатись у допустиму довжину коментарів, тому я просто скопіював перший та останній рядок)
Kmeixner

1
Я створив приклад Plunker коду, щоб ви могли порівняти його зі своїм кодом. plnkr.co/edit/tN0156hRfX0M6k9peQ2C?p=preview
Arnoud Sietsema

21

Короткий спосіб зробити це було б використовувати метод _.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>

1
@jwoodward Він ніколи не говорив, що це не варіант. Моє рішення на сьогоднішній день є найпростішим і найбільш перевіреним завдяки тестуванню одиниць від їх репо. Ви завжди можете взяти js з незміненої бібліотеки і включити її як функцію.
Майкл Дж. Калкінс

4
Щоправда, він ніколи цього не казав. Але взагалі погана ідея вирішити проблему в одній бібліотеці, застосувавши іншу бібліотеку, вона просто заважає вам навчитися правильно користуватися першою бібліотекою. Зверніться до іншої бібліотеки, коли / якщо немає хорошого рішення в поточній.
Ерік Гонн

5
Я вже використовую лодаш скрізь, цей був, безумовно, найпростішим рішенням. Дякую. Я щойно зробив $ range.range = _.range, тоді його легко використовувати у будь-якому шаблоні з динамічними значеннями старту / кінця.
j_walker_dev

2
@ErikHonn: UnderscoreJS вирішує зовсім іншу проблему для AngularJS. Немає хорошого рішення для генерації діапазонів у AngularJS, оскільки це не є метою бібліотеки.
AlexFoxGill

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 + ']');не працює ...
Стефан Уолтер

"Я використовую...". Ви насправді намагалися ним користуватися? Атрибут ng-повтор не буде складений.
Пітер Хедберг

Дякую Пітер, Ive оновив код. Раніше я використовував цю директиву, але вона все ще залишила моє сховище коду
pleerock,

9

Найпростішим рішенням без коду було запровадити масив з діапазоном і використовувати $ index + скільки б я не хотів компенсувати:

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

7

Визначення методу

Нижче наведений код визначає метод, range()доступний для всієї сфери вашої програми MyApp. Його поведінка дуже схожа на 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 )

$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

Привіт, ви можете досягти цього за допомогою чистого 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>

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

Вдосконалення рішення @ Мормегіла

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 робить це для вас.
мацько

2
Дякуємо за те, що зробили свій внесок, але якщо припустити, що ОП знає coffeescript, що це таке, як скласти його назад до JS, або коли-небудь використовував будь-які інструменти побудови, такі, як це величезна розтяжка. Ми всі тут, щоб навчитися чи допомогти, тож пройдіть зайву милю, перетворіть цього цуценя. (Ви подали позов!)
Аугі Гарднер

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


0

Припустимо $scope.refernceurl, це масив

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

-8

Це найпростіший варіант: просто використовуйте масив цілих чисел ....

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


3
Це жахливо.
Тіффані Лоу

@Stefan, ви, ймовірно, отримуєте зворотній зв'язок, оскільки рішення не може використовувати жорстко кодовані колекції.
Тасс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.