43

I want to have several datepickers on a page. But with the default solution from UI-Bootstrap it is not possible, no one of datepickers may be opened. The conflict with each other. Here is my code:

<div>
            <div class="form-horizontal pull-left">
                <input type="text" datepicker-popup="dd-MMMM-yyyy" ng-model="dt" is-open="opened" min="minDate" max="'2015-06-22'" datepicker-options="dateOptions" date-disabled="disabled(date, mode)" ng-required="true"/>
                <button class="btn" ng-click="open()"><span class="glyphicon glyphicon-calendar"></span></button>
            </div>
            <div class="form-horizontal pull-left">
                <input type="text" datepicker-popup="dd-MMMM-yyyy" ng-model="dt" is-open="opened" min="minDate" max="'2015-06-22'" datepicker-options="dateOptions" date-disabled="disabled(date, mode)" ng-required="true" />
                <button class="btn" ng-click="open()"><span class="glyphicon glyphicon-calendar"></span></button>
            </div>
            <button type="submit" class="btn btn-default">Submit</button>
        </div>

I just did a copy/paste of the datepicker code from the site http://angular-ui.github.io/bootstrap/#/datepicker. They conflict with each other. When I click <input> field to open a datepicker no one can be opened properly, both are opened for a second and immediately disappear.

How may I have several datepickers on a single page?

Green
  • 28,742
  • 61
  • 158
  • 247
  • 1
    You should probably assign them to different ng-models. – aet Oct 27 '13 at 00:57
  • 8
    agree with @aet and also use a different `is-open` variable for each – charlietfl Oct 27 '13 at 01:26
  • Have you found solution? If yes, please describe it. – christof Jan 03 '14 at 07:48
  • 1
    The solution is to use a different variable for the ```is-open``` attribute. If you don't do that the ui-bootstrap stuff can't keep up with which one is open. @Green should select one of the answers below as the accepted answer. – boatcoder Jul 16 '14 at 03:02
  • possible duplicate of [How to usemultiple Angular UI Bootstrap Datepicker in single form?](http://stackoverflow.com/questions/22269964/how-to-usemultiple-angular-ui-bootstrap-datepicker-in-single-form) – Gaurav Gandhi Sep 22 '15 at 11:58

7 Answers7

79

Rather than using a different function you can use a different is-open attribute and then pass the attribute in through the ng-click function. You still need different models:

<div>
        <div class="form-horizontal pull-left">
            <input type="text" datepicker-popup="dd-MMMM-yyyy" ng-model="dt1" is-open="opened1" min="minDate" max="'2015-06-22'" datepicker-options="dateOptions" date-disabled="disabled(date, mode)" ng-required="true"/>
            <button class="btn" ng-click="open($event,'opened1')"><span class="glyphicon glyphicon-calendar"></span></button>
        </div>
        <div class="form-horizontal pull-left">
            <input type="text" datepicker-popup="dd-MMMM-yyyy" ng-model="dt2" is-open="opened2" min="minDate" max="'2015-06-22'" datepicker-options="dateOptions" date-disabled="disabled(date, mode)" ng-required="true" />
            <button class="btn" ng-click="open($event,'opened2')"><span class="glyphicon glyphicon-calendar"></span></button>
        </div>
        <button type="submit" class="btn btn-default">Submit</button>
    </div>

And inside controller:

   $scope.open = function($event,opened) {
    $event.preventDefault();
    $event.stopPropagation();

    $scope[opened] = true;
  };
Matt
  • 9,068
  • 12
  • 64
  • 84
BlueMonk
  • 791
  • 6
  • 3
15

I'm still learning Angular and UI-Bootstrap, so take that into account when reading my answer. I did something similar to BlueMonk, but in a flexible way that keeps my controller code from having to know about the instances of the datepicker on the page.

I put all of the datepicker code in my controller into a single namespace:

$scope.datePicker = (function () {
    var method = {};
    method.instances = [];

    method.open = function ($event, instance) {
        $event.preventDefault();
        $event.stopPropagation();

        method.instances[instance] = true;
    };

    method.options = {
        'show-weeks': false,
        startingDay: 0
    };

    var formats = ['MM/dd/yyyy', 'dd-MMMM-yyyy', 'yyyy/MM/dd', 'dd.MM.yyyy', 'shortDate'];
    method.format = formats[0];

    return method;
}());

And then used the following markup:

<p class="input-group">
    <input type="text" class="form-control" ng-model="editableEmployee.dateHired" datepicker-popup="{{datePicker.format}}" datepicker-options="datePicker.options" is-open="datePicker.instances['dateHired']" close-text="Close" />
    <span class="input-group-btn">
        <button type="button" class="btn btn-default" ng-click="datePicker.open($event, 'dateHired')"><i class="glyphicon glyphicon-calendar"></i></button>
    </span>
</p>

<p class="input-group">
    <input type="text" class="form-control" ng-model="editableEmployee.dateFired" datepicker-popup="{{datePicker.format}}" datepicker-options="datePicker.options" is-open="datePicker.instances['dateFired']" close-text="Close" />
    <span class="input-group-btn">
        <button type="button" class="btn btn-default" ng-click="datePicker.open($event, 'dateFired')"><i class="glyphicon glyphicon-calendar"></i></button>
    </span>
</p>

This worked like a charm for me.

  • Thank you very much and quite creative. :) – Robbie Smith Apr 07 '15 at 05:52
  • @JerryBensonMontgome my use case involves a dynamic set of rows that can grow (by clicking Add Another button), wherein one column corresponds to a date field that must be enriched by a datepicker. In that case, how do I use your elegant approach? – Web User Apr 15 '15 at 22:05
  • If you just pass in a custom string for each row (where I have 'dateHired' and 'dateFired') you should be fine. I typically use some static text concatenated with some sort of row id when I do this type of thing. Heck, a randomly generated number would work because I don't think you (as the developer) ever need to know what it is. I haven't used this solution in a scenario like yours, but I think it should work. – Jerry Benson-Montgomery Apr 16 '15 at 23:19
  • This looks very elegant, but I get an undefined error on this line: method.instances[instance] = true; – Will Strohl Oct 03 '15 at 20:33
  • I've asked a follow-up question here: http://stackoverflow.com/questions/32927394/typeerror-undefined-on-module-pattern-of-object-instances – Will Strohl Oct 03 '15 at 20:53
10

This should work (different models, open flag, and functions):

<div>
        <div class="form-horizontal pull-left">
            <input type="text" datepicker-popup="dd-MMMM-yyyy" ng-model="dt1" is-open="opened1" min="minDate" max="'2015-06-22'" datepicker-options="dateOptions" date-disabled="disabled(date, mode)" ng-required="true"/>
            <button class="btn" ng-click="open1()"><span class="glyphicon glyphicon-calendar"></span></button>
        </div>
        <div class="form-horizontal pull-left">
            <input type="text" datepicker-popup="dd-MMMM-yyyy" ng-model="dt2" is-open="opened2" min="minDate" max="'2015-06-22'" datepicker-options="dateOptions" date-disabled="disabled(date, mode)" ng-required="true" />
            <button class="btn" ng-click="open2()"><span class="glyphicon glyphicon-calendar"></span></button>
        </div>
        <button type="submit" class="btn btn-default">Submit</button>
    </div>

And inside controller:

   $scope.open1 = function($event) {
    $event.preventDefault();
    $event.stopPropagation();

    $scope.opened1 = true;
  };

   $scope.open2 = function($event) {
    $event.preventDefault();
    $event.stopPropagation();

    $scope.opened2 = true;
  };
Kath
  • 1,834
  • 15
  • 17
  • This should not work, and should throw 'preventDefault' of undefined. to solve the error you pass $event to your functions. It still wont solve the problem. As the two will still conflict. It didnt work for me. – Jay Nov 13 '14 at 12:36
  • This isn't very DRY. I prefer BlueMonk's answer. – Jason Swett Mar 05 '15 at 22:56
  • This works. But you have to pass $event into `open1($event)` and `open2($event)` functions. – Wild Goat Aug 02 '15 at 13:24
1

Here is what worked for me: $id is scope id, provided by angular.

    ctrl.opened = {};
    ctrl.openDatatimePicker = function ($event, id) {
        $event.preventDefault();
        $event.stopPropagation();
        ctrl.opened[id] = true;
    }
                                            <input type="text" 
                                                   class="form-control" 
                                                   uib-datepicker-popup="{{vm.datepickerFormat}}"
                                                   ng-model="x.FraDato" 
                                                   is-open="vm.opened[$id]"
                                                   datepicker-options="vm.datepickerOptions"
                                                   ng-required="true" 
                                                   ng-click="vm.openDatatimePicker($event,$id)"/>
Amr Ellafy
  • 730
  • 8
  • 26
0

No Additional changes are necessary. As long as you wrap each date input in it's own controller div the scope will reside with that input

Example:

<div ng-controller="DatepickerDemoCtrl">
    <div class="form-horizontal pull-left">
        <input type="text" datepicker-popup="dd-MMMM-yyyy" ng-model="dt" is-open="opened" min="minDate" max="'2015-06-22'" datepicker-options="dateOptions" date-disabled="disabled(date, mode)" ng-required="true"/>
        <button class="btn" ng-click="open($event)"><span class="glyphicon glyphicon-calendar"></span></button>
    </div>
</div>
<div ng-controller="DatepickerDemoCtrl">
    <div class="form-horizontal pull-left">
        <input type="text" datepicker-popup="dd-MMMM-yyyy" ng-model="dt" is-open="opened" min="minDate" max="'2015-06-22'" datepicker-options="dateOptions" date-disabled="disabled(date, mode)" ng-required="true" />
        <button class="btn" ng-click="open($event)"><span class="glyphicon glyphicon-calendar"></span></button>
    </div>
</div>
Zanderi
  • 907
  • 9
  • 15
  • Actually he does have to make changes, ng-model="dt" buried in another controller like that will be useless. He needs to use ```something.startOn```, ```something.endOn``` so the variables are made available on the surrounding scope. Otherwise this is a pretty cool trick with controllers. – boatcoder Jul 16 '14 at 03:05
0

though its an old question but answring for someone who fall in to same problem as i did.

i assigned the datepicker onfocus to that element and it workd great. Sample code.

   $(document).on('focus','.datepicker',function(){
        $(this).datepicker();
   });
Ashutosh Raj
  • 1,045
  • 1
  • 11
  • 21
0

Can open multi datepickers of ui-bootstrap on a single page

JS

  $scope.open = {};
  $scope.openCalendar = function (e, date) {
    e.preventDefault();
    e.stopPropagation();

    if ($scope.open[date] === true) {
      $scope.open = {};
    } else {
      $scope.open = {};
      $scope.open[date] = true;
    }
  };

HTML

<input type="text" id="created1" name="created1" datetime-picker="" datepicker-options="dateOptions" timepicker-options="timeOptions" ng-click="openCalendar($event, 'created1')" placeholder="0000/00/00 00:00" is-open="open.created1" autocomplete="off" class="form-control" ng-model="vm.condition.created1">

<input type="text" id="created2" name="created2" datetime-picker="" datepicker-options="dateOptions" timepicker-options="timeOptions" ng-click="openCalendar($event, 'created2')" placeholder="0000/00/00 00:00" is-open="open.created2" autocomplete="off" class="form-control" ng-model="vm.condition.created2">
Tính Ngô Quang
  • 4,400
  • 1
  • 33
  • 33