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>

ใช้งานได้ แต่ไม่จำเป็นเนื่องจากเราจะไม่ใช้อาร์เรย์ช่วงเลยในลูป ไม่มีใครรู้ว่าการตั้งค่าช่วงหรือปกติสำหรับค่าต่ำสุด / สูงสุด?

สิ่งที่ต้องการ:

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

2
นี่คือข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้ yearofmoo.com/2012/10/…
matsko

คำตอบ:


281

ฉัน tweaked คำตอบนี้เล็กน้อยและเกิดขึ้นกับซอนี้

ตัวกรองกำหนดเป็น:

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
น่าเกลียดน่ากลัว! ;) ตัวกรองไม่ใช่วิธีการทำเช่นนี้ มันควรจะเป็นคุณลักษณะใหม่ที่ทำงานกับสองค่า ดัชนีปัจจุบันและขอบเขตบน
Ian Warburton

10
@IanWarburton คุณสามารถหาคำตอบที่ตรงกับเกณฑ์ของคุณหรือไม่?
น้ำค้าง

1
@IanWarburton: มีคำตอบจากУmedด้านล่างที่ใช้งานได้กับคำสั่งคุณไม่สามารถทำงานได้
Andresch Serj

1
ฉันต้องการช่วงระหว่าง A และ B ดังนั้นฉันจึงทวี
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
คุณสามารถลดจำนวนเยี่ยมชมได้โดยการแคชผลลัพธ์ผ่านทางรูปแบบบันทึกช่วยจำ ไม่แน่ใจว่าราคาหน่วยความจำคืออะไร แต่เป็นการปรับปรุง en.wikipedia.org/wiki/Memoization
Joshua

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 และมันก็ใช้ได้ ฉันเชื่อว่าพวกเขาได้ปรับปรุง parser ดังนั้นจึงไม่ปฏิเสธการเข้าถึง 'constructor' ทุกคน แต่มีเพียงสิ่งที่อันตรายจริงๆ (เช่น[].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

หนึ่งและสองกรณีพระรามรักษา 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

2
เมื่อฉันพยายามเรียกใช้รหัสนี้ใน Chrome ฉันได้รับข้อผิดพลาดในคอนโซล: ข้อผิดพลาด: [$ injector: unpr] errors.angularjs.org/1.2.6/$injector/ … ... ที่ Wa.statements ( ajax.googleapis.com/ajax/libs/angularjs/1.2.6/… ) <! - ngRepeat: 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 เขาไม่เคยบอกว่าไม่ใช่ตัวเลือก โซลูชันของฉันนั้นง่ายที่สุดและผ่านการทดสอบมากที่สุดเนื่องจากการทดสอบหน่วยจาก repo ของพวกเขา คุณสามารถนำ js ออกจากไลบรารีที่ไม่ได้ระบุและรวมไว้เป็นฟังก์ชัน
Michael J. Calkins

4
จริงเขาไม่เคยพูดอย่างนั้น แต่โดยทั่วไปแล้วมันเป็นความคิดที่ดีที่จะแก้ปัญหาในห้องสมุดหนึ่งโดยใช้ห้องสมุดอื่นมันแค่ป้องกันไม่ให้คุณเรียนรู้วิธีการใช้ห้องสมุดแห่งแรกอย่างถูกต้อง ไปที่ห้องสมุดอื่นเมื่อ / หากไม่มีวิธีแก้ปัญหาที่ดีในห้องสมุดปัจจุบัน
Erik Honn

5
ฉันใช้ lodash แล้วทุกที่อันนี้เป็นทางออกที่ง่ายที่สุด ขอบคุณ. ฉันเพิ่งได้ $ scope.range = _.range แล้วมันใช้งานง่ายในเทมเพลตใด ๆ ที่มีค่าเริ่มต้น / สิ้นสุดแบบไดนามิก
j_walker_dev

2
@ErikHonn: ขีดล่าง JS แก้ปัญหาที่แตกต่างอย่างสิ้นเชิงกับ 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-repeat จะไม่ถูกรวบรวม
Peter Hedberg

ขอบคุณ Peter ฉันได้อัพเดตโค้ดแล้ว ฉันเคยใช้คำสั่งนี้ในอดีต แต่ก็ยังเหลือที่เก็บรหัสของฉัน
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()วิธี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,



6

ไม่มีการเปลี่ยนแปลงใด ๆ ในคอนโทรลเลอร์ของคุณคุณสามารถใช้สิ่งนี้:

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

สนุก!


ได้รับการดิ้นรนมากขึ้นกว่าวันและในที่สุดก็เพียง แต่รูปแบบนี้ทำงานให้ฉัน
Agnel Amodia

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

สวัสดีคุณสามารถทำได้โดยใช้ 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

การปรับปรุงโซลูชันของ @ 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 -2

<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

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
นี่มันช่างน่ากลัว
Tiffany Lowe

@Stefan คุณน่าจะได้รับ downvotes เพราะโซลูชันไม่สามารถใช้คอลเลกชันแบบตายตัวได้
Tass
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.