web-dev-qa-db-de.com

Angular.js und HTML5-Datumseingabewert - Wie wird Firefox dazu gebracht, einen lesbaren Datumswert in einer Datumseingabe anzuzeigen?

Ich habe eine HTML5-Datumseingabe und möchte, dass der Wert standardmäßig auf den Wert der Datumseigenschaft in meinem Modell festgelegt wird. Ich bin nicht allzu pingelig in der Formatierung, da Chrome das für mich sowieso basierend auf meinem Gebietsschema zu entscheiden scheint, aber im Idealfall wäre das Format durchgehend dd/MM/yyyy.

Fiddle

So richte ich meine Eingabe ein:

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

Dies funktioniert in Chrome einwandfrei und ich sehe standardmäßig Folgendes:

Chrome displaying the formatted value of the date

(Ich verstehe immer noch nicht ganz, warum der Wert in yyyy-MM-dd angegeben werden musste, wenn Chrome ihn immer noch basierend auf meinem Gebietsschema formatiert, aber das ist eine andere Frage.

Mein Problem ist, dass Firefox den Datumswert nicht so anzeigt, wie ich es angegeben habe. Ich denke, dies hat mit der Bindung der Eingabe an das Modell date zu tun, da ich im Attribut value so gut wie jede Zeichenfolge angeben kann und die lange Datumszeichenfolge standardmäßig in der Eingabe angezeigt wird:

Firefox showing datestring

Wenn ich ng-model="date" aus dem Eingabe-Tag entferne, zeigt Firefox jeden Wert an, den ich ihm gebe. Ich hätte nicht gedacht, dass das Modell, an das eine Eingabe gebunden ist, tatsächlich Auswirkungen auf den Standardwert hat.

Ich verstehe, dass die Datumseingabe nicht allgemein unterstützt wird, aber da sie auf eine einfache Texteingabe zurückgreifen soll, verstehe ich nicht, warum der Wert nicht einfach 2013-08-05 lautet, wie vom Datumsfilter von angle angegeben.

Wie bringe ich Firefox dazu, meinen formatierten Wert bei der Datumseingabe zu akzeptieren?


NOTENachdem der Benutzer die Änderungen vorgenommen hat, werde ich natürlich eine Validierung durchführen und jeden Datumseingabewert in ein richtiges Objekt Date konvertieren. Ich bin mir nicht sicher, ob dies für die Frage relevant ist, stelle es aber für alle Fälle zur Verfügung, da die Eingabeformate offensichtlich konsistent sein müssten, damit die Datumskonvertierung in allen Browsern gleich funktioniert. Problematisch ist natürlich, dass Chrome das Eingabeformat für mich festgelegt hat ...

64
Elise

Das Problem ist, dass value wird ignoriert, wenn ng-model vorhanden ist .

Firefox, das derzeit type="date" nicht unterstützt, konvertiert alle Werte in Zeichenfolgen. Da Sie (zu Recht) möchten, dass date ein echtes Date-Objekt und kein String ist, ist es meiner Meinung nach die beste Wahl, eine andere Variable zu erstellen, zum Beispiel dateString, und dann die beiden Variablen zu verknüpfen:

<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

Die tatsächliche Struktur dient nur zu Demonstrationszwecken. Es ist besser, wenn Sie eine eigene Direktive erstellen, insbesondere um:

Bitte beachten Sie, dass ich yyyy-MM-dd verwendet habe, da dieses Format direkt vom JavaScript-Objekt Date unterstützt wird. Wenn Sie einen anderen verwenden möchten, müssen Sie die Konvertierung vornehmen sich.


EDIT

Hier ist eine Möglichkeit, eine saubere Direktive zu erstellen:

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

Das ist eine grundlegende Richtlinie, es gibt noch viel Raum für Verbesserungen, zum Beispiel:

  • die Verwendung eines benutzerdefinierten Formats anstelle von yyyy-MM-dd zulassen,
  • überprüfen Sie, ob das vom Benutzer eingegebene Datum korrekt ist.
72
Blackhole

Warum musste der Wert in JJJJ-MM-TT angegeben werden?

Gemäß dem input type = Datumsangabe von HTML 5 muss der Wert im Format yyyy-MM-dd sein, da er das Format eines gültigen full-date annimmt, der in RFC3339 als angegeben ist 

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

Mit Angularjs hat dies nichts zu tun, da die Anweisungseingabe den Typ date nicht unterstützt. 

Wie kann Firefox meinen formatierten Wert bei der Datumseingabe akzeptieren?

FF unterstützt mindestens bis zur Version 24.0 den Typ date nicht. Diese Informationen erhalten Sie von hier . Wenn Sie also die Eingabe mit dem Typ date in FF verwenden, nimmt das Textfeld den Wert an, den Sie übergeben.

Mein Vorschlag ist, Sie können Angular-ui's Timepicker verwenden und nicht die HTML5-Unterstützung für die Datumseingabe verwenden.

12
zsong

Sie können dies verwenden, es funktioniert gut: 

<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>

In meinem Fall habe ich diesen Weg gelöst:

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

und Datum der Eingabe ist in Ordnung

1

Ich habe ng-change verwendet:

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

Überprüfen Sie diese voll funktionsfähige Direktive auf MEAN.JS (Angular.js, bootstrap, Express.js und MongoDb).

Basierend auf der Antwort von @Blackhole haben wir es gerade fertiggestellt, um es mit mongodb und express zu verwenden.

Damit können Sie Daten von einem Moose-Connector speichern und laden 

Ich hoffe es hilft!!

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);
        })

      }
    };
  });

Die JADE/HTML:

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

Wenn Sie Angular Material Design verwenden, können Sie dort die Datepicker-Komponente verwenden. Dies funktioniert in Firefox, IE usw.

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

Eine faire Warnung - persönliche Erfahrung ist, dass es Probleme gibt, und es wird anscheinend derzeit überarbeitet. Siehe hier:

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

0
John Rix