web-dev-qa-db-fra.com

Comment utiliser plusieurs Angular UI Bootstrap Datepicker sous une forme unique?

J'ai un formulaire où il est nécessaire d'avoir 2 champs de date ou plus pour différentes choses. J'ai essayé le Bootstrap d'interface utilisateur angulaire qui fonctionne bien lorsque je n'ai qu'un seul champ de date dans le formulaire. Mais cela cesse de fonctionner si j'ai plusieurs champs de date et que je ne connais pas la méthode la plus simple pour que cela fonctionne. 

Voici mon exemple HTML:

 <label>First Date</label>  
    <div class="input-group">
     <input type="text" class="form-control" datepicker-popup="{{format}}" name="dt" ng-model="formData.dt" is-open="opened" datepicker-options="dateOptions" ng-required="true" close-text="Close" />
      <span class="input-group-btn">
        <button class="btn btn-default" ng-click="open($event)"><i class="glyphicon glyphicon-calendar"></i></button>
      </span>
    </div>      

 <label>Second Date</label>  
    <div class="input-group">
     <input type="text" class="form-control" datepicker-popup="{{format}}" name="dtSecond" ng-model="formData.dtSecond" is-open="opened" datepicker-options="dateOptions" ng-required="true" close-text="Close" />
      <span class="input-group-btn">
        <button class="btn btn-default" ng-click="open($event)"><i class="glyphicon glyphicon-calendar"></i></button>
      </span>
    </div>     

Mon JS est: 

myApp.controller('DatePickrCntrl', function ($scope) {

      $scope.today = function() {
        $scope.formData.dt = new Date();
      };
      $scope.today();

      $scope.showWeeks = true;
      $scope.toggleWeeks = function () {
        $scope.showWeeks = ! $scope.showWeeks;
      };

      $scope.clear = function () {
        $scope.dt = null;
      };

      // Disable weekend selection
      $scope.disabled = function(date, mode) {
        return ( mode === 'day' && ( date.getDay() === 0 || date.getDay() === 6 ) );
      };

      $scope.toggleMin = function() {
        $scope.minDate = ( $scope.minDate ) ? null : new Date();
      };
      $scope.toggleMin();

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

        $scope.opened = true;
      };

      $scope.dateOptions = {
        'year-format': "'yy'",
        'starting-day': 1
      };

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

});

J'ai mis en œuvre sur la base de l'échantillon ici . Le problème que j'ai ici est: 

1) Lorsque l’un des champs de date est cliqué, le sélecteur de date contextuel est modifié et semble afficher 2 sélecteur de date sur 1. 

2) Lorsque je supprime l'attribut is-open="opened", la fenêtre contextuelle semble fonctionner correctement. Mais sans is-open="opened", la ng-click="open($event) du bouton ne fonctionne pas.

3) Étant donné que chaque champ de date a un modèle différent, je ne peux pas définir de date par défaut pour les champs de date, à l'exception du premier avec ng-model="formData.dt"

Le seul moyen de résoudre ce problème auquel je peux penser est de séparer le contrôleur pour chaque champ de date. 

J'aimerais savoir comment d'autres utilisateurs implémentent plusieurs champs de date dans un même formulaire lors de l'utilisation de Angular UI Bootstrap.

24
Neel

J'ai 30 dans un formulaire, un contrôleur sans problème. utilisez le même concept si vous en avez besoin sur ng-repeat.

 <label>First Date</label>  
    <div class="input-group">
     <input type="text" class="form-control" datepicker-popup="{{format}}" 
            name="dt" ng-model="formData.dt" is-open="datepickers.dt" 
            datepicker-options="dateOptions" ng-required="true" 
            close-text="Close" />
      <span class="input-group-btn">
        <button class="btn btn-default" ng-click="open($event,'dt')">
            <i class="glyphicon glyphicon-calendar"></i></button>
      </span>
    </div>      

 <label>Second Date</label>  
    <div class="input-group">
     <input type="text" class="form-control" datepicker-popup="{{format}}" 
            name="dtSecond" ng-model="formData.dtSecond" 
            is-open="datepickers.dtSecond" datepicker-options="dateOptions" 
            ng-required="true" close-text="Close" />
      <span class="input-group-btn">
        <button class="btn btn-default" ng-click="open($event,'dtSecond')">
            <i class="glyphicon glyphicon-calendar"></i></button>
      </span>
    </div>     

myApp.controller('DatePickrCntrl', function ($scope) {
      $scope.datepickers = {
        dt: false,
        dtSecond: false
      }
      $scope.today = function() {
        $scope.formData.dt = new Date();

        // ***** Q1  *****
        $scope.formData.dtSecond = new Date();
      };
      $scope.today();

      $scope.showWeeks = true;
      $scope.toggleWeeks = function () {
        $scope.showWeeks = ! $scope.showWeeks;
      };

      $scope.clear = function () {
        $scope.dt = null;
      };

      // Disable weekend selection
      $scope.disabled = function(date, mode) {
        return ( mode === 'day' && ( date.getDay() === 0 || date.getDay() === 6 ) );
      };

      $scope.toggleMin = function() {
        $scope.minDate = ( $scope.minDate ) ? null : new Date();
      };
      $scope.toggleMin();

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

        $scope.datepickers[which]= true;
      };

      $scope.dateOptions = {
        'year-format': "'yy'",
        'starting-day': 1
      };

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

});


 // ***** Q2 ***** somemodel can be just an array [1,2,3,4,5]
 <div ng-repeat="o in somemodel">
 <label>Date Label</label>  
    <div class="input-group">
     <input type="text" class="form-control" datepicker-popup="{{format}}"
            name="dt{{o}}" ng-model="datepickers.data[o]" 
            is-open="datepickers.isopen[o]" datepicker-options="datepickers.option" 
            ng-required="true" close-text="Close" />
      <span class="input-group-btn">
        <button class="btn btn-default" ng-click="open($event,o)">
            <i class="glyphicon glyphicon-calendar"></i></button>
      </span>
    </div>
  </div>


myApp.controller('DatePickrCntrl', function ($scope) {

      $scope.datepickers = {
        data: {},
        options: {
            'year-format': "'yy'",
            'starting-day': 1
        },
        isopen: {}
      }
      $http.get("get/data/for/some/model", function(result) {
         $scope.somemodel = result;
         for (var i = 0; i < result.length; i++) {
           $scope.datepickers.isopen[result] = false;
           $scope.datepickers.data[result] = new Date(); //set default date.
         }
      });

  // fill in rest of the function
});
42
wayne

Solution plus simple. Ne nécessite que la modification du code HTML et peut être utilisé dans une répétition si vous le souhaitez. Sois juste créatif avec ce que tu appelles ouvert

Collez ceci dans votre contrôleur:

$scope.calendar = {
    opened: {},
    dateFormat: 'MM/dd/yyyy',
    dateOptions: {},
    open: function($event, which) {
        $event.preventDefault();
        $event.stopPropagation();
        $scope.calendar.opened[which] = true;
    } 
};

HTML:

<div class="form-group row">
    <div class="col-lg-6">
        <label for="formDOB">Date of Birth</label>
        <p class="input-group">
          <input type="text" class="form-control" datepicker-popup="{{calendar.dateFormat}}" ng-model="record.birthDate" is-open="calendar.opened.dob" datepicker-options="calendar.dateOptions" close-text="Close" placeholder="Date of Birth" />
          <span class="input-group-btn">
            <button type="button" class="btn btn-default" ng-click="calendar.open($event, 'dob')"><i class="glyphicon glyphicon-calendar"></i></button>
          </span>
        </p>
    </div>
    <div class="col-lg-6">
        <label for="formWinDate">Win Date</label>
        <p class="input-group">
          <input type="text" class="form-control" datepicker-popup="{{calendar.dateFormat}}" ng-model="record.winDate" is-open="calendar.opened.win" datepicker-options="calendar.dateOptions" close-text="Close" placeholder="Win DAte" />
          <span class="input-group-btn">
            <button type="button" class="btn btn-default" ng-click="calendar.open($event, 'win')"><i class="glyphicon glyphicon-calendar"></i></button>
          </span>
        </p>
    </div>
</div>
19
geilt

La réponse de wayne est excellente. J'ajouterai simplement que vous pouvez améliorer la fonction 'open ()':

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

    $scope.closeAll();
    datePicker.opened = true;
};

Et puis vous devez l'utiliser comme ça:

ng-click="open($event, dateFrom)"

Où dateDe est votre modèle-ng (c’est-à-dire que vous utilisez $ scope.dateFrom).

EDIT: $scope.closeAll(); est une fonction qui ferme tous les datePickers. Cela peut être écrit comme ça:

$scope.closeAll = function() {
    $scope.dateFrom.opened = false;
    $scope.dateTo.opened = false;
};
5
Mateusz Rasiński

Je préférerais ne pas mélanger ng-model avec les informations d'interface utilisateur. Dans ce but, il est nécessaire de définir un tableau pour stocker les indicateurs d'ouverture, ainsi que de vérifier si le datePicker est ouvert ou non. 

De plus, j’ai modifié le comportement «ouvert» pour le «basculer» à la place, afin de permettre de fermer le datePicker avec le bouton. 

Voici mon contrôleur:

$scope.toggleOpenDatePicker = function($event,datePicker) {
   $event.preventDefault();
   $event.stopPropagation();
   $scope[datePicker] = !$scope[datePicker];
};

Ensuite, il peut être utilisé comme:

<input type="text" class="form-control" ng-model="model.date1" is-open="date1" />
   <span class="input-group-btn">
      <button type="button" class="btn btn-default" ng-click="toggleOpenDatePicker($event,'date1')"><i class="glyphicon glyphicon-calendar"></i>      
      </button>
   </span>

L'idée $ scope a été empruntée à ici :

2
Toni Gamez

J'ai résolu mon problème en utilisant ce plunker avec des modifications mineures.

HTML

<div class="row">
    <div class="col-md-6">
        <p class="input-group">
          <input type="text" class="form-control" datepicker-popup="{{format}}" ng-model="dt" is-open="openDatePickers[0]" min-date="minDate" max-date="'2015-06-22'" datepicker-options="dateOptions" date-disabled="disabled(date, mode)" ng-required="true" close-text="Close" />
          <span class="input-group-btn">
            <button type="button" class="btn btn-default" ng-click="open($event, 0)"><i class="glyphicon glyphicon-calendar"></i></button>
          </span>
        </p>
    </div>
</div>
    <h4>Popup</h4>
<div class="row">
    <div class="col-md-6">
        <p class="input-group">
          <input type="text" class="form-control" datepicker-popup="{{format}}" ng-model="dt" is-open="openDatePickers[1]" min-date="minDate" max-date="'2015-06-22'" datepicker-options="dateOptions" date-disabled="disabled(date, mode)" ng-required="true" close-text="Close" />
          <span class="input-group-btn">
            <button type="button" class="btn btn-default" ng-click="open($event, 1)"><i class="glyphicon glyphicon-calendar"></i></button>
          </span>
        </p>
    </div>
</div>

et dans le contrôleur

$scope.openDatePickers = [];
$scope.open = function ($event, datePickerIndex) {
   $event.preventDefault();
   $event.stopPropagation();

   if ($scope.openDatePickers[datePickerIndex] === true) {
      $scope.openDatePickers.length = 0;
   } else {
      $scope.openDatePickers.length = 0;
      $scope.openDatePickers[datePickerIndex] = true;
   }
};

mes modifications

à la place des nombres (0 ou 1), j’utilise $index en angulaire ng-repeat.

comme ça: 

is-open="openDatePickers[**$index**]"

ng-click="open($event, **$index**)"

<p class="input-group">
   <input type="text" class="form-control" datepicker-popup="{{format}}" ng-model="dt" is-open="openDatePickers[$index]" min-date="minDate" max-date="'2015-06-22'" datepicker-options="dateOptions" date-disabled="disabled(date, mode)" ng-required="true" close-text="Close">
   <span class="input-group-btn">
      <button type="button" class="btn btn-default" ng-click="open($event, $index)"><i class="glyphicon glyphicon-calendar"></i></button>
   </span>
</p>
1

je l'ai utilisé d'une manière différente et cela me semble un peu plus facile. J'utilisais l'une des approches mentionnées, mais j'étais trop paresseux pour créer des tonnes de calendriers, car j'utilisais une boucle sans identificateur statique . calendriers à l'intérieur d'un ng-repeat. J'espère que ça aide!

C'est le contrôleur

       $scope.datepickers = {
            data: {},
            isopen: {}
       }
       // setting the defaults once
       for (var i = 0; i < $scope.array.length; i++) {
            $scope.datepickers.isopen[i] = false;
            $scope.datepickers.data[i] = new Date();
        }

        // aso..

        $scope.valuationDatePickerOpen = function($event, index) {
          if ($event) {
            $event.preventDefault();
            $event.stopPropagation();
          }
          $scope.datepickers.isopen[index] = true;
        };

Et voici le code HTML inséré dans ma boucle

<!-- ng-repeat="entry in array track by $index" --> 

<input type="text" class="form-control" 
       datepicker-popup="dd-MMMM-yyyy" 
       is-open="datepickers.isopen[$index]"
       ng-click="valuationDatePickerOpen($event, $index)"
       ng-model="entry.date" />
0
djnose