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.