I need to create a 3 birthday fields (days,month,years) and as I am using AngularJS I thought I can use the ngRepeat directive with an expression like i < 31 or so. But it does not work.
Does someone have an idea what I can do to simply fill a dropdown box with all the needed values ?
Thanks!
ng-repeat is not the way to go really. Rather use the ng-options directive passing in an expression that pulls the labels from an array in the model of the controller.
First construct the controller that will hold the arrays for the Years, Months and Days. Create properties on the $scope object so you can access those arrays through the ng-options directive on the view.
If you include JQuery as a dependency you can construct your arrays the following way:
var years = $.map($(Array(numberOfYears)), function (val, i) { return i + 1900; });
var months = $.map($(Array(12)), function (val, i) { return i + 1; });
var days = $.map($(Array(31)), function (val, i) { return i + 1; });
If you prefer not to have a JQuery dependency just use a good old for loop for all three arrays. The following code will give you an accessors on the $scope for the arrays:
$scope.Years = years;
$scope.Months = months;
$scope.Days = days;
Back in your HTML view add a select element with the ng-options and ng-model ng-options directives for example:
<div class="ng-scope" ng-controller="BirthdayController">
<select ng-model="SelectedYear" ng-options="label for label in Years"></select>
<select ng-model="SelectedMonth" ng-options="label for label in Months"></select>
<select ng-model="SelectedDays" ng-options="label for label in Days"></select>
</div>
I am assuming you are familiar with creating AngularJS modules and adding controllers to it as well as adding the necessary ng-app directive, ng-scope class and ng-controller directives to the containers. Up to this point you will have three drop down lists containing a list of years, a list of 12 months and a list of 31 days respectively. If you want to have a dependent day list keep reading! :)
Refer to this plnkr for the basic version: http://plnkr.co/edit/VfEpwPv084H7XiifEsnm?p=preview
Bonus round:
You can take this one step further and make the days show correct number of days since days really has a dependency on the month and year selected. February has 28 days on non leap years and 29 days on leap years. Other months have 30 or 31 days depending on the month. If you want to go all fancy you need a function in the controller to determine leap years and to determine how many days to return to calculate whether a year is a leap year in javascript the following function is quite useful:
var isLeapYear = function (selectedYear) {
var year = SelectedYear || 0;
return ((year % 400 == 0 || year % 100 != 0) && (year % 4 == 0)) ? 1 : 0;}
Although it will look slightly different using Angular since the $scope will already contain the selectedYear and won't have to be passed in. The isLeapYear helper function is accessed by another function which determines how many days to display for the given month and year combination as follows:
var getNumberOfDaysInMonth = function (selectedMonth) {
var selectedMonth = selectedMonth || 0;
return 31 - ((selectedMonth === 2) ? (3 - isLeapYear()) : ((selectedMonth - 1) % 7 % 2));}
Now all that needs to be done on the original select element for days would be to add a limitTo filter on the ng-options directive to change how many elements are actually rendered. The Select element for Months and Years require a ng-Change directive so we can update the field on the $scope which will hold the number to limit the days by.
<select ng-model="SelectedYear" ng-options="label for label in Years" ng-change="UpdateNumberOfDays()"></select>
<select ng-model="SelectedMonth" ng-options="label for label in Months" ng-change="UpdateNumberOfDays()"></select>
<select ng-model="SelectedDays" ng-options="label for label in Days | limitTo:NumberOfDays"></select>
Where NumberOfDays is populated in the function on the controller $scope.UpdateNumberOfDays() which of course will utilize the helper function GetNumberOfDaysInMonth described above.
And as an extra bonus here is a plnkr for the smart version: http://plnkr.co/edit/AENh6Ynj4kNKZfLsXx4N?p=preview
Enjoy!
Can you just use a DatePicker?
You can use the select directive in combination with an array of numbers to bind to. This post shows both a function and a filter that you can use to fill from 1-31.
Here is the basic syntax of the select binding to an array:
<select ng-model="selected" ng-options="n for n in [1, 2, 3, 4, 5, 6]"></select>
Note the drop down doesn't appear to populate if you omit the ng-model
.
As others have mentioned using a date picker is a good option you can use the AngularUI wrapper directive for the jQuery UI Datepicker found here.
My approach to this involved having the days select list populated using the following:
<select class="form-control" ng-model="birthdate.day"
ng-options="day for day in birthDays()">
</select>
And on the controller the birthDays() function is:
$scope.birthDays = function () {
var year = parseInt($scope.birthdate.year, 10);
var month = parseInt($scope.birthdate.month, 10);
var num = new Date(year, month + 1, 0).getDate();
var i;
var days = [];
for (i = 1; i <= num; i++) {days.push(String(i)); }
return days;
};