web-dev-qa-db-fra.com

Angular.js et valeur d'entrée de date HTML5: comment obtenir de Firefox qu'il affiche une valeur de date lisible dans une entrée de date?

J'ai une entrée de date au format HTML5 et j'aimerais que sa valeur soit définie par défaut sur la valeur de la propriété date de mon modèle. Le formatage ne me pose pas trop de problèmes, car Chrome semble en avoir décidé autrement en fonction de mes paramètres régionaux, mais idéalement, le format serait toujours dd/MM/yyyy.

Fiddle

Voici comment j'ai configuré mon entrée:

<input type="date" 
       ng-model="date" 
       value="{{ date | date: 'yyyy-MM-dd' }}" />

Cela fonctionne bien sur Chrome et je vois par défaut ce qui suit:

Chrome displaying the formatted value of the date

(Je ne comprends toujours pas pourquoi la valeur doit être donnée dans yyyy-MM-dd, si Chrome la formate toujours en fonction de mes paramètres régionaux, mais c'est une question différente.)

Mon problème est avec Firefox ne pas afficher la valeur de la date de la manière que j'ai spécifiée. Je pense que cela a à voir avec la liaison de l'entrée au modèle date, parce que je peux spécifier à peu près n'importe quelle chaîne dans l'attribut value, et je verrai toujours la chaîne de date longue dans l'entrée par défaut:

Firefox showing datestring

Si je supprime ng-model="date" de la balise d’entrée, Firefox affiche joliment toutes les valeurs que je lui donne. Je ne pensais pas que le modèle auquel une entrée était liée avait réellement un effet sur sa valeur par défaut?

Je comprends que la saisie de date n'est pas prise en charge de manière universelle, mais vu qu'elle est supposée s'appuyer sur une saisie de texte simple, je ne vois pas pourquoi sa valeur ne serait pas simplement 2013-08-05, comme spécifié par le filtre de date d'angular.

Alors, comment faire pour que Firefox accepte ma valeur formatée dans l'entrée de date?


NOTE Une fois les modifications effectuées par l'utilisateur, je vais bien sûr effectuer une validation et convertir chaque valeur entrée en date en un objet Date approprié. Je ne suis pas sûr que cela soit pertinent pour la question, mais il faut l'indiquer au cas où, car les formats d'entrée auraient évidemment besoin d'être cohérents pour que la conversion de date fonctionne de la même manière dans tous les navigateurs. Problématique, bien sûr, avec Chrome qui décidait pour moi du format d'entrée ...

64
Elise

Le problème est que value est ignoré lorsque ng-model est présent .

Firefox, qui ne supporte pas actuellement type="date", convertira toutes les valeurs en chaîne. Puisque vous voulez (à juste titre) que date soit un véritable objet Date et non une chaîne, le meilleur choix est de créer une autre variable, par exemple dateString, puis de lier les deux variables:

<input type="date" ng-model="dateString" />
function MainCtrl($scope, dateFilter) {
    $scope.date = new Date();

    $scope.$watch('date', function (date)
    {
        $scope.dateString = dateFilter(date, 'yyyy-MM-dd');
    });

    $scope.$watch('dateString', function (dateString)
    {
        $scope.date = new Date(dateString);
    });
}

Fiddle

La structure actuelle est uniquement à des fins de démonstration. Vous feriez mieux de créer votre propre directive, notamment pour:

Veuillez noter que j'ai utilisé yyyy-MM-dd, car c'est un format directement pris en charge par l'objet JavaScript Date. Si vous souhaitez en utiliser un autre, vous devez effectuer la conversion vous-même.


EDIT

Voici un moyen de faire une directive propre:

myModule.directive(
    'dateInput',
    function(dateFilter) {
        return {
            require: 'ngModel',
            template: '<input type="date"></input>',
            replace: true,
            link: function(scope, Elm, attrs, ngModelCtrl) {
                ngModelCtrl.$formatters.unshift(function (modelValue) {
                    return dateFilter(modelValue, 'yyyy-MM-dd');
                });

                ngModelCtrl.$parsers.unshift(function(viewValue) {
                    return new Date(viewValue);
                });
            },
        };
});

Fiddle

C'est une directive de base, il y a encore beaucoup à faire, par exemple:

  • autoriser l'utilisation d'un format personnalisé au lieu de yyyy-MM-dd,
  • vérifiez que la date saisie par l'utilisateur est correcte.
72
Blackhole

Pourquoi la valeur devait être donnée en aaaa-MM-jj?

Selon le type d'entrée = date spéc de HTML 5, la valeur doit être au format yyyy-MM-dd puisqu'elle prend le format d'un full-date valide spécifié dans RFC3339 as 

full-date = date-fullyear "-" date-month "-" date-mday

Il n'y a rien à faire avec Angularjs puisque l'entrée de directive ne supporte pas le type date

Comment faire en sorte que Firefox accepte ma valeur formatée lors de la saisie de la date?

FF ne prend pas en charge le type d'entrée date pour au moins la version 24.0. Vous pouvez obtenir cette information de ici . Donc, pour le moment, si vous utilisez une entrée dont le type est date dans FF, la zone de texte prend la valeur que vous transmettez.

Ma suggestion est que vous pouvez utiliser Timepicker d'angular-ui et ne pas utiliser le support HTML5 pour la saisie de la date.

12
zsong

Vous pouvez l'utiliser, cela fonctionne très bien: 

<input type="date" class="form1"  
  value="{{date | date:MM/dd/yyyy}}"
  ng-model="date" 
  name="id" 
  validatedateformat 
  data-date-format="mm/dd/yyyy"
  maxlength="10" 
  id="id" 
  calendar 
  maxdate="todays"
  ng-click="openCalendar('id')">
    <span class="input-group-addon">
      <span class="glyphicon glyphicon-calendar" ng-click="openCalendar('id')"></span>
    </span>
</input>

Dans mon cas, j'ai résolu de cette façon:

$scope.MyObject = // get from database or other sources;
$scope.MyObject.Date = new Date($scope.MyObject.Date);

et la date de type d'entrée est ok

1
Giovanni De Rosa

J'ai utilisé ng-change:

Date.prototype.addDays = function(days) {
  var dat = new Date(this.valueOf());
  dat.setDate(dat.getDate() + days);
  return dat;
}

var app = angular.module('myApp', []);

app.controller('DateController', ['$rootScope', '$scope',
  function($rootScope, $scope) {
    function init() {
      $scope.startDate = new Date();
      $scope.endDate = $scope.startDate.addDays(14);
    }


    function load() {
      alert($scope.startDate);
      alert($scope.endDate);
    }

    init();
    // public methods
    $scope.load = load;
    $scope.setStart = function(date) {
      $scope.startDate = date;
    };
    $scope.setEnd = function(date) {
      $scope.endDate = date;
    };

  }
]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div data-ng-controller="DateController">
  <label class="item-input"> <span class="input-label">Start</span>
    <input type="date" data-ng-model="startDate" ng-change="setStart(startDate)" required validatedateformat calendar>
  </label>
  <label class="item-input"> <span class="input-label">End</span>
    <input type="date" data-ng-model="endDate" ng-change="setEnd(endDate)" required validatedateformat calendar>
  </label>
  <button button="button" ng-disabled="planningForm.$invalid" ng-click="load()" class="button button-positive">
    Run
  </button>
</div <label class="item-input"> <span class="input-label">Start</span>
<input type="date" data-ng-model="startDate" ng-change="setStart(startDate)" required validatedateformat calendar>
</label>
<label class="item-input"> <span class="input-label">End</span>
  <input type="date" data-ng-model="endDate" ng-change="setEnd(endDate)" required validatedateformat calendar>
</label>

0
hypery2k

Vérifiez cette directive entièrement fonctionnelle pour MEAN.JS (Angular.js, bootstrap, Express.js et MongoDb)

Basé sur la réponse de @Blackhole, nous venons de le finir pour l’utiliser avec mongodb et express.

Il vous permettra de sauvegarder et de charger des dates à partir d'un connecteur de mangouste 

J'espère que ça aide!!

angular.module('myApp')
.directive(
  'dateInput',
  function(dateFilter) {
    return {
      require: 'ngModel',
      template: '<input type="date" class="form-control"></input>',
      replace: true,
      link: function(scope, Elm, attrs, ngModelCtrl) {
        ngModelCtrl.$formatters.unshift(function (modelValue) {
          return dateFilter(modelValue, 'yyyy-MM-dd');
        });

        ngModelCtrl.$parsers.Push(function(modelValue){
           return angular.toJson(modelValue,true)
          .substring(1,angular.toJson(modelValue).length-1);
        })

      }
    };
  });

Le JADE/HTML:

div(date-input, ng-model="modelDate")

Si vous utilisez Angular Material Design, vous pouvez utiliser le composant datepicker et cela fonctionnera sous Firefox, IE, etc.

https://material.angularjs.org/latest/demo/datepicker

Avertissement juste, l'expérience personnelle montre qu'il y a des problèmes avec cela, et apparemment, cela est en train d'être retravaillé à l'heure actuelle. Vois ici:

https://github.com/angular/material/issues/4856

0
John Rix