Come formattare una data usando ng-model?


93

Ho un input definito come

<input class="datepicker" type="text" ng-model="clientForm.birthDate" />

Che è truccato per essere visualizzato altrove nella pagina:

<tr>
    <th>Birth Date</th>
    <td>{{client.birthDate|date:'mediumDate'}}</td>
</tr>

Quando la pagina viene caricata, la data di nascita è ben formattata come qualcosa di simile Dec 22, 2009. Tuttavia, quando guardo dentro il mio, <input>viene mostrato come Tue Dec 22 2009 00:00:00 GMT-0800 (Pacific Standard Time)immagino sia il modo in cui JS rende gli Dateoggetti come stringhe.

In primo luogo, come faccio a dire ad Angular di mostrare la data in <input>qualcosa di simile 12/22/2009? Non riesco ad applicare |filtersall'interno ng-modeldell'attributo.

In secondo luogo, non appena modifico la data, pur mantenendola nel suo formato originale, l'altro mio testo (all'interno di <td>) sembra non applicare più il |datefiltro; cambia improvvisamente i formati per abbinare quello della casella di testo di input. Come faccio ad applicare il |datefiltro ogni volta che il modello cambia?


Domande correlate:


Ho anche avuto un problema su questo, ma ho fornito una soluzione più semplice utilizzando le Date()funzioni js standard : $scope.departDate = new Date(); $scope.departTime = $scope.departDate.toTimeString().slice(0, 5);e non sono necessari altri filtri o soluzioni alternative complicate in AngularJS IMO.
boldnik

Risposte:


71

Utilizza la convalida personalizzata dei moduli http://docs.angularjs.org/guide/forms Demo: http://plnkr.co/edit/NzeauIDVHlgeb6qF75hX?p=preview

Direttiva che utilizza formattatori e parser e MomentJS )

angModule.directive('moDateInput', function ($window) {
    return {
        require:'^ngModel',
        restrict:'A',
        link:function (scope, elm, attrs, ctrl) {
            var moment = $window.moment;
            var dateFormat = attrs.moDateInput;
            attrs.$observe('moDateInput', function (newValue) {
                if (dateFormat == newValue || !ctrl.$modelValue) return;
                dateFormat = newValue;
                ctrl.$modelValue = new Date(ctrl.$setViewValue);
            });

            ctrl.$formatters.unshift(function (modelValue) {
                if (!dateFormat || !modelValue) return "";
                var retVal = moment(modelValue).format(dateFormat);
                return retVal;
            });

            ctrl.$parsers.unshift(function (viewValue) {
                var date = moment(viewValue, dateFormat);
                return (date && date.isValid() && date.year() > 1950 ) ? date.toDate() : "";
            });
        }
    };
});

4
Volevo creare un piccolo esempio di formater e parser, grazie alla tua domanda di oggi ho avuto il motivo per farlo.
SunnyShah

1
@ Mark, risolto il problema di Nan nel secondo violino. ;)
SunnyShah

1
Secondo approccio rimosso. Era troppo pieno di bug.
SunnyShah

1
È possibile utilizzare la direttiva in caso di modifica per apportare ulteriori miglioramenti. stackoverflow.com/questions/14477904/...
SunnyShah

7
@SunnyShah - ottima roba, davvero utile, grazie mille. Mi chiedevo perché hai var dateFormat = attrs.moMediumDate;e non var dateFormat = attrs.moDateInput;moMediumDate non sembra essere impostato da nessuna parte, quindi se gli input non vengono creati dinamicamente non viene mai selezionato un formato iniziale.
toxaq

37

Ecco una direttiva molto utile angular-datetime . Puoi usarlo in questo modo:

<input type="text" datetime="yyyy-MM-dd HH:mm:ss" ng-model="myDate">

Inoltre aggiunge una maschera al tuo input ed esegue la convalida.


1
Ho usato anche questa direttiva, grazie. Se lo stai utilizzando con jQuery UI Datepicker, devi assicurarti che il formato specificato nel datetime="<format>"valore dell'attributo corrisponda al formato specificato nell'opzione Datepicker dateFormat.
tylerwal

1
Mi chiedo come sia possibile che qui ci sia una soluzione perfetta con solo pochi voti positivi. Questo per quanto riguarda le date, e puoi risolverle proprio qui, subito! Grazie amico.
C0ZEN

2
Sono sicuro che più persone voterebbero, se la documentazione fosse migliorata per renderla più facile da includere in un'app angolare esistente.
Joel Hansen

8

Ho creato una semplice direttiva per consentire agli input[type="date"]elementi del modulo standard di funzionare correttamente con AngularJS ~ 1.2.16.

Guarda qui: https://github.com/betsol/angular-input-date

Ed ecco la demo: http://jsfiddle.net/F2LcY/1/


Hey @Lorenzo, cosa intendi? Potresti elaborare per favore?
Slava Fomin II

Il mese dell'anno è in francese come Lun Mar Mer per Lun Mar, Mer
Merlin

@Lorenzo non sono sicuro di non vedermi. La direttiva non ha nulla a che fare con la localizzazione. Probabilmente la funzione di formattazione che stai utilizzando sta prendendo le impostazioni locali dal tuo browser / sistema. Se fornisci un esempio sarò in grado di aiutarti (jsfiddle).
Slava Fomin II

1
supporta solo Chrome, così male.
GeminiYellow

L'obiettivo della direttiva è supportare tutte le piattaforme. Se hai problemi con esso, perché non crei un problema sul repository GitHub? Rispondo sempre a tutti i problemi.
Slava Fomin II

7

Sto usando jquery datepicker per selezionare la data. La mia direttiva legge la data e la converte in formato data json (in millisecondi) memorizza nei ng-modeldati mentre visualizza la data formattata e inverte se ng-model ha data json (in millisecondi) il mio formattatore visualizza nel mio formato come datepicker jquery.

Codice HTML:

<input type="text" jqdatepicker  ng-model="course.launchDate" required readonly />

Direttiva angolare:

myModule.directive('jqdatepicker', function ($filter) {
    return {
        restrict: 'A',
        require: 'ngModel',
         link: function (scope, element, attrs, ngModelCtrl) {
            element.datepicker({
                dateFormat: 'dd/mm/yy',
                onSelect: function (date) {   
                    var ar=date.split("/");
                    date=new Date(ar[2]+"-"+ar[1]+"-"+ar[0]);
                    ngModelCtrl.$setViewValue(date.getTime());            
                    scope.$apply();
                }
            });
            ngModelCtrl.$formatters.unshift(function(v) {
            return $filter('date')(v,'dd/MM/yyyy'); 
            });

        }
    };
});

Oh mio Dio!! Grazie mille !! Ho letteralmente cercato per due giorni qualcosa di simile a questa risposta, ma non sono riuscito a trovarne una! Sei forte!
Michael Rentmeister

Fantastico. Ho cercato qualcosa di simile per un po '. Sto usando materializecss per la mia soluzione. Se qualcuno si imbatte in questo e ha bisogno di convertire questa direttiva per materializzarsi, sostituisci element.datepickerconelement.pickadate
IWI

7

Dato che hai usato datepicker come classe, presumo che tu stia usando un datepicker Jquery o qualcosa di simile.

C'è un modo per fare ciò che intendi senza utilizzare moment.js, utilizzando esclusivamente le direttive datepicker e angularjs.

Ho dato un esempio qui in questo violino

Estratti dal violino qui:

  1. Datepicker ha un formato diverso e il formato angularjs è diverso, è necessario trovare la corrispondenza appropriata in modo che la data sia preselezionata nel controllo e sia anche popolata nel campo di input mentre il modello ng è associato. Il formato seguente è equivalente al 'mediumDate'formato di AngularJS.

    $(element).find(".datepicker")
              .datepicker({
                 dateFormat: 'M d, yy'
              }); 
  2. La direttiva di input della data deve avere una variabile stringa temporanea per rappresentare la forma leggibile della data.

  3. L'aggiornamento in diverse sezioni della pagina dovrebbe avvenire tramite eventi, come $broadcaste $on.

  4. L'uso del filtro per rappresentare la data in un formato leggibile dall'uomo è possibile anche in ng-model, ma con una variabile di modello temporanea.

    $scope.dateValString = $filter('date')($scope.dateVal, 'mediumDate');

6

Uso la seguente direttiva che rende me e la maggior parte degli utenti molto felici! Utilizza il momento per l'analisi e la formattazione. Assomiglia un po 'a quello di SunnyShah, menzionato in precedenza.

angular.module('app.directives')

.directive('appDatetime', function ($window) {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function (scope, element, attrs, ngModel) {
            var moment = $window.moment;

            ngModel.$formatters.push(formatter);
            ngModel.$parsers.push(parser);

            element.on('change', function (e) {
                var element = e.target;
                element.value = formatter(ngModel.$modelValue);
            });

            function parser(value) {
                var m = moment(value);
                var valid = m.isValid();
                ngModel.$setValidity('datetime', valid);
                if (valid) return m.valueOf();
                else return value;
            }

            function formatter(value) {
                var m = moment(value);
                var valid = m.isValid();
                if (valid) return m.format("LLLL");
                else return value;

            }

        } //link
    };

}); //appDatetime

Nella mia forma lo uso in questo modo:

<label>begin: <input type="text" ng-model="doc.begin" app-datetime required /></label>
<label>end: <input type="text" ng-model="doc.end" app-datetime required /></label>

Questo legherà un timestamp (millisecondi dal 1970) a doc.begine doc.end.


1
È facile trascurare il fatto che, all'interno di questa funzione di collegamento, ngModelc'è il tuo identificatore personalizzato per l'argomento del controller, non un riferimento diretto e denominato a ngModel. Questo è un punto in cui la convenzione di denominare che arg "ctrl" o "controller" mantiene le cose più chiare ed evita confusione.
XML

Grazie! Ho cercato tutto il giorno un modo carino per farlo. Sfortunatamente, la maggior parte delle altre correzioni comportava il passaggio a un datepicker scritto appositamente per angular, e questo era troppo lavoro.
Josh Mouch

Ho provato sia la tua risposta che quella di @SunnyShah, ma la sua non sembra funzionare. Non so perché.
Josh Mouch

3

In Angular2 + per chiunque sia interessato:

<input type="text" placeholder="My Date" [ngModel]="myDate | date: 'longDate'">

con il tipo di filtri in DatePipe Angular.


Dang, sono bloccato nell'eredità AngularJS su cui sono stato costretto a lavorare, e lo odio! Vorrei poter lavorare con quanto sopra.
Jordan

Questo è solo prendere in giro le persone e indurle a usare Angular2 +. Che schifo! AngularJs è totalmente la bomba. Perché qualcuno dovrebbe volere una soluzione semplice come questa.
Nebulosar

2

Preferisco che il server restituisca la data senza modifiche e che javascript esegua il massaggio della vista. La mia API restituisce "MM / DD / YYYY hh: mm: ss" da SQL Server.

Risorsa

angular.module('myApp').factory('myResource',
    function($resource) {
        return $resource('api/myRestEndpoint/', null,
        {
            'GET': { method: 'GET' },
            'QUERY': { method: 'GET', isArray: true },
            'POST': { method: 'POST' },
            'PUT': { method: 'PUT' },
            'DELETE': { method: 'DELETE' }
        });
    }
);

Controller

var getHttpJson = function () {
    return myResource.GET().$promise.then(
        function (response) {

            if (response.myDateExample) {
                response.myDateExample = $filter('date')(new Date(response.myDateExample), 'M/d/yyyy');
            };

            $scope.myModel= response;
        },
        function (response) {
            console.log(response.data);
        }
    );
};

Direttiva sulla convalida di myDate

angular.module('myApp').directive('myDate',
    function($window) {
        return {
            require: 'ngModel',
            link: function(scope, element, attrs, ngModel) {

                var moment = $window.moment;

                var acceptableFormats = ['M/D/YYYY', 'M-D-YYYY'];

                function isDate(value) {

                    var m = moment(value, acceptableFormats, true);

                    var isValid = m.isValid();

                    //console.log(value);
                    //console.log(isValid);

                    return isValid;

                };

                ngModel.$parsers.push(function(value) {

                    if (!value || value.length === 0) {
                         return value;
                    };

                    if (isDate(value)) {
                        ngModel.$setValidity('myDate', true);
                    } else {
                        ngModel.$setValidity('myDate', false);
                    }

                    return value;

                });

            }
        }
    }
);

HTML

<div class="form-group">
    <label for="myDateExample">My Date Example</label>
    <input id="myDateExample"
           name="myDateExample"
           class="form-control"
           required=""
           my-date
           maxlength="50"
           ng-model="myModel.myDateExample"
           type="text" />
    <div ng-messages="myForm.myDateExample.$error" ng-if="myForm.$submitted || myForm.myDateExample.$touched" class="errors">
        <div ng-messages-include="template/validation/messages.html"></div>
    </div>
</div>

template / validation / messages.html

<div ng-message="required">Required Field</div>
<div ng-message="number">Must be a number</div>
<div ng-message="email">Must be a valid email address</div>
<div ng-message="minlength">The data entered is too short</div>
<div ng-message="maxlength">The data entered is too long</div>
<div ng-message="myDate">Must be a valid date</div>

1

Angularjs ui bootstrap puoi usare angularjs ui bootstrap, fornisce anche la convalida della data

<input type="text"  class="form-control" 
datepicker-popup="{{format}}" ng-model="dt" is-open="opened" 
min-date="minDate" max-date="'2015-06-22'"  datepickeroptions="dateOptions"
date-disabled="disabled(date, mode)" ng-required="true"> 



nel controller puoi specificare il formato in cui desideri visualizzare la data come datefilter

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


non è necessario implementare la direttiva solo per un singolo campo di input
P.JAYASRI
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.