4

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!

4 Answers4

4

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!

sbarnard
  • 385
  • 3
  • 11
0

Can you just use a DatePicker?

http://www.nsftools.com/tips/DatePickerTest.htm

alexgerst
  • 155
  • 1
  • 11
  • It might work, but it also might be a bit more work instead of using a simple angularjs expression if there is one... –  Jul 31 '12 at 14:30
  • 1
    I would use a date picker anytime for this kind of feature. – Lajos Arpad Jul 31 '12 at 14:45
  • 3
    I disagree, a DatePicker does not give an easy way to select year. I would either use a select with ng-options as Gloopy mentions, or use a UI mask for manual type in http://angular-ui.github.com/#directives-mask – beatn1ck Nov 29 '12 at 20:55
  • 3
    Date pickers are not a user-friendly approach to date of birth entry. – Richard Jones Feb 26 '14 at 04:06
0

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.

Community
  • 1
  • 1
Gloopy
  • 37,767
  • 15
  • 103
  • 71
  • Thanks! We actually removed angularjs and work with jQuery only now. For us this was a simple step and seems pretty easy for now and it worked for us directly. But I will test this at home for sure... –  Aug 01 '12 at 12:35
0

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;
};
Richard Jones
  • 400
  • 1
  • 5