42

I am trying to create a select element that has a list of numbers 1 to pages where pages is a variable that is the number of pages I have. What i don't know how to do is to structure the ng-options expression so that it will give me the numbers I need. Here is what I have so far

<select ng-model="page" ng-options="???"></select>

what do I need to put in the ng-options expression in order for it to create my select like

<select>
    <option value="1">1</option>
    ...
    <option value="35">35</option>
</select>

do I need to create a function that returns an array of numbers and use it in there somehow or is there an easier way to do this?

any help would be greatly appreciated.

Thanks

EDIT

After posting my question i figured out one way to do it by creating a function called Range in my controller that takes two numbers and returns an array with all the values in that range.

$scope.Range = function(start, end) {
    var result = [];
    for (var i = start; i <= end; i++) {
        result.push(i);
    }
    return result;
};

then in the HTML I did

<select ng-name="page" ng-options="page for page in Range(1, pages)"></select> 

Is this the simplest way to do this or is there a better way?

Nakilon
  • 34,866
  • 14
  • 107
  • 142
d_boggus
  • 1,019
  • 2
  • 9
  • 21
  • 1
    This is a clever parlor trick, but why not just use an HTML input of type number? You can even specify a range. – Kraken Nov 29 '15 at 12:42

8 Answers8

82

Your way works fine. Another option that came to my head is to use a filter, so you don't have to pollute your controller with Range.

JS:

var myApp = angular.module('myApp', []);
myApp.filter('range', function() {
  return function(input, min, max) {
    min = parseInt(min); //Make string input int
    max = parseInt(max);
    for (var i=min; i<max; i++)
      input.push(i);
    return input;
  };
});

HTML:

<select ng-model="page" ng-options="n for n in [] | range:1:30"></select>

Example: http://jsfiddle.net/N3ZVp/1/

P.S. in your example in your main post, you didn't put var in front of i. So i is declared as a global variable in your example.

EpokK
  • 38,062
  • 9
  • 61
  • 69
Andrew Joslin
  • 43,033
  • 21
  • 100
  • 75
  • This is nice but how do I use the filter in the ng-options? I have about 1300 pages so I can't just list them all out and I need to be able to jump to any page so using a select element is my only real option. Fixed the undeclared variable in my for stmt. – d_boggus Jun 22 '12 at 19:28
  • I tried that in jsfiddle and it doesn't work. [http://jsfiddle.net/J4AYh/](http://jsfiddle.net/J4AYh/). **Edit:** However I was able to get it to work on my page. Could you make a working example on jsfiddle? – d_boggus Jun 22 '12 at 21:03
  • I dunno why that's not working. I guess your Range function is the best. – Andrew Joslin Jun 22 '12 at 21:56
  • Well your filter method worked on my site, I just couldn't get it to work in jsfiddle which I though was odd. I haven't used jsfiddle much so I wasn't sure if it was just me doing something wrong or not. Thanks for your answer. – d_boggus Jun 23 '12 at 04:50
  • I wrote a nice version in CoffeeScript: https://gist.github.com/Dorian/311c7563fe6af6563d6f – Dorian Jun 18 '14 at 22:24
  • 2
    The range in your jsfiddle example is inclusive (i<=max vs. i – phatfingers Sep 15 '14 at 20:57
14

Another solution to keep it all in your template:

<select>
  <option ng-repeat="n in [].constructor(10) track by $index+1">{{$index+1}}</option>
</select>
Adam Boostani
  • 5,999
  • 9
  • 38
  • 44
8

Please add ng-model, like below

<select ng-model="test" ng-options="n for n in [] | range:1:30"></select>

After this your example will work in jsfiddle

user2003449
  • 81
  • 1
  • 1
7

another approach without a for loop is this:

controller:

 $scope.arr = [];
 $scope.arr.length = count;

view binding:

 ng-options="arr.indexof(i) for i in arr"
CodeToad
  • 4,656
  • 6
  • 41
  • 53
7

Andy's solution is great, however the range cannot go backwards. Here's the improved version:

/* 
 * Creates a range
 * Usage example: <option ng-repeat="y in [] | range:1998:1900">{{y}}</option>
 */
myApp.filter('range', function() {
  return function(input, start, end) {    
    start = parseInt(start);
    end = parseInt(end);
    var direction = (start <= end) ? 1 : -1;
    while (start != end) {
        input.push(start);
        start += direction;
    }
    return input;
  };
});
martynas
  • 12,120
  • 3
  • 55
  • 60
5

Piggybacking on martynas' answer. I modified it to include the last value in the range:

/*
 * Creates a range
 * Usage example: <option ng-repeat="y in [] | range:1998:1900">{{y}}</option>
 */

.filter('range', function () {
    return function (input, start, end) {
        var direction;

        start = parseInt(start);
        end = parseInt(end);

        if (start === end) { return [start]; }

        direction = (start <= end) ? 1 : -1;

        while (start != end) {
            input.push(start);

            if (direction < 0 && start === end + 1) {
                input.push(end);
            }

            if (direction > 0 && start === end - 1) {
                input.push(end);
            }

            start += direction;
        }

        return input;
    };
});
Rob Evans
  • 6,750
  • 4
  • 39
  • 56
Johnny
  • 1,141
  • 9
  • 6
  • Almost perfect, but returns empty array if start=end. Add the following after the parseInts to fix: `if(start===end) return [start];` – Konamiman Sep 11 '15 at 10:35
0

In CoffeeScript:

app.filter 'range', ->
  (input, min, max) ->
    input.push(i) for i in [parseInt(min)..parseInt(max)]

And the HTML:

<select ng-options="n for n in [] | range:1:30"></select>

Here is the gist with the Javascript

Dorian
  • 22,759
  • 8
  • 120
  • 116
0

If you want to add a placeholder in select, then use below given solution. You need to first define the filter like this.

<select>
    <option value="">-- Birth Year --</option>
    <option ng-repeat="n in [] | range:1900:2000">{{n}}</option>
</select>
Community
  • 1
  • 1
Farhan Ghumra
  • 15,180
  • 6
  • 50
  • 115