Jak sformatować datę za pomocą modelu ng?


94

Mam dane wejściowe zdefiniowane jako

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

Który jest skonfigurowany do wyświetlania w innym miejscu na stronie:

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

Kiedy strona się ładuje, data urodzenia jest ładnie sformatowana jako coś podobnego Dec 22, 2009. Jednak kiedy patrzę do środka <input>, widać Tue Dec 22 2009 00:00:00 GMT-0800 (Pacific Standard Time), że wydaje mi się, że JS renderuje Dateobiekty jako ciągi.

Po pierwsze, jak mam powiedzieć Angularowi, żeby pokazywał datę <input>jako coś podobnego 12/22/2009? Nie mogę zastosować |filterswewnątrz ng-modelatrybutu.

Po drugie, gdy tylko edytuję datę, nawet zachowując ją w oryginalnym formacie, mój drugi tekst (wewnątrz <td>) nie wydaje się już stosować |datefiltra; nagle zmienia format, aby dopasować go do pola tekstowego wejściowego. Jak mam zastosować |datefiltr za każdym razem, gdy model się zmienia?


Powiązane pytania:


Miałem też z tym problem, ale otrzymałem prostsze rozwiązanie wykorzystujące standardowe Date()funkcje js : $scope.departDate = new Date(); $scope.departTime = $scope.departDate.toTimeString().slice(0, 5);i nie ma potrzeby stosowania innych filtrów lub trudnych obejść w AngularJS IMO.
— boldnik

Odpowiedzi:


71

Użyj niestandardowej walidacji formularzy http://docs.angularjs.org/guide/forms Demo: http://plnkr.co/edit/NzeauIDVHlgeb6qF75hX?p=preview

Dyrektywa wykorzystująca formatery i parsery oraz 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
Chciałem stworzyć mały przykład formatera i parsera, dzięki twojemu pytaniu mam dziś powód, aby to zrobić.
— SunnyShah

1
@Mark, Naprawiono problem z Nan w drugich skrzypcach. ;)
— SunnyShah

1
Usunięto drugie podejście. To było zbyt zapchane.
— SunnyShah

1
Możesz użyć dyrektywy przy zmianie, aby wprowadzić dalsze ulepszenia. stackoverflow.com/questions/14477904/…
— SunnyShah

7
@SunnyShah - świetne rzeczy, bardzo pomocne, bardzo dziękuję. Zastanawiałem się, dlaczego masz, var dateFormat = attrs.moMediumDate;a nie, var dateFormat = attrs.moDateInput;moMediumDate nie wydaje się być nigdzie ustawione, więc jeśli dane wejściowe nie są tworzone dynamicznie, format początkowy nigdy nie jest wybierany.
— toxaq

37

Tutaj jest bardzo przydatna dyrektywa kątowa-data-godzina . Możesz go używać w ten sposób:

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

Dodaje również maskę do danych wejściowych i przeprowadza walidację.


1
Skorzystałem również z tej dyrektywy, dzięki. Jeśli używasz go z Datepicker interfejsu użytkownika jQuery, musisz upewnić się, że format określony w datetime="<format>"wartości atrybutu jest zgodny z formatem określonym w opcji Datepicker dateFormat.
— tylerwal

1
Zastanawiam się, jak to możliwe, że jest tutaj idealne rozwiązanie z zaledwie kilkoma głosami pozytywnymi. Tyle na temat dat, a możesz je rozwiązać tutaj, teraz! Dzięki stary.
— C0ZEN

2
Jestem pewien, że więcej osób zagłosowałoby za tym, gdyby dokumentacja została ulepszona, aby ułatwić włączenie do istniejącej aplikacji kątowej.
— Joel Hansen,

8

Stworzyłem prostą dyrektywę, aby umożliwić input[type="date"]poprawną pracę standardowych elementów formularzy z AngularJS ~ 1.2.16.

Zajrzyj tutaj: https://github.com/betsol/angular-input-date

A oto demo: http://jsfiddle.net/F2LcY/1/


Hej @Lorenzo, co masz na myśli? Czy mógłbyś to rozwinąć?
— Slava Fomin II

Dzień miesiąca i roku są w języku francuskim, jak Lun Mar Mer dla Mon Tue, Wen
— Merlin

@Lorenzo Nie jestem pewien, czy nie rozumiem. Dyrektywa nie ma nic wspólnego z lokalizacją. Prawdopodobnie funkcja formatowania, której używasz, pobiera ustawienia regionalne z przeglądarki / systemu. Jeśli podasz przykład, będę w stanie pomóc (jsfiddle).
— Slava Fomin II

1
po prostu obsługuj chrome, tak źle.
— GeminiYellow

Celem dyrektywy jest wsparcie wszystkich platform. Jeśli masz z tym problemy, dlaczego nie utworzysz problemu w repozytorium GitHub? Zawsze odpowiadam na wszystkie problemy.
— Slava Fomin II

7

Do wyboru daty używam jquery datepicker. Moja dyrektywa odczytuje datę i konwertuje ją na format daty json (w milisekundach), przechowując w ng-modeldanych podczas wyświetlania sformatowanej daty. I odwracaj, jeśli model ng ma datę JSON (w milisekundach), mój formater wyświetla w moim formacie jako jquery datepicker.

Kod HTML:

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

Dyrektywa kątowa:

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

        }
    };
});

O mój Boże!! Dziękuję bardzo !! Dosłownie przez dwa dni szukałem czegoś takiego jak ta odpowiedź, ale nie mogłem jej znaleźć! Rządzisz!
— Michael Rentmeister

Fantastyczny. Od jakiegoś czasu szukałem czegoś takiego. Używam materializecss do mojego rozwiązania. Jeśli ktoś stubles na tej i potrzeb przekonwertować tę dyrektywę do urzeczywistnią, po prostu zamienić się element.datepickerzelement.pickadate
— IWI

7

Ponieważ użyłeś Datepicker jako klasy, zakładam, że używasz Jquery Datepicker lub czegoś podobnego.

Istnieje sposób na zrobienie tego, co zamierzasz, bez używania w ogóle moment.js, używając wyłącznie dyrektyw datepicker i angularjs.

Podałem tutaj przykład w tym skrzypcach

Fragmenty ze skrzypiec tutaj:

  1. Datepicker ma inny format, a format angularjs jest inny, należy znaleźć odpowiednie dopasowanie, aby data została wstępnie wybrana w kontrolce i jest również wypełniana w polu wejściowym, gdy model ng jest związany. Poniższy format jest odpowiednikiem 'mediumDate'formatu AngularJS.

    $(element).find(".datepicker")
              .datepicker({
                 dateFormat: 'M d, yy'
              }); 
    
  2. Dyrektywa wejściowa daty musi mieć tymczasową zmienną łańcuchową, która reprezentuje datę w postaci czytelnej dla człowieka.

  3. Odświeżanie w różnych sekcjach strony powinno odbywać się za pośrednictwem wydarzeń, takich jak $broadcasti $on.

  4. Użycie filtru do przedstawienia daty w postaci czytelnej dla człowieka jest również możliwe w modelu ng, ale z tymczasową zmienną modelu.

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

6

Używam następującej dyrektywy, która bardzo mnie cieszy i większość użytkowników! Wykorzystuje moment do analizowania i formatowania. Wygląda trochę jak wspomniany wcześniej SunnyShah.

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

W mojej formie używam tego w ten sposób:

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

Spowoduje to powiązanie znacznika czasu (w milisekundach od 1970 r.) Z doc.begini doc.end.


1
Łatwo przeoczyć fakt, że wewnątrz tej funkcji łączenia ngModelznajduje się niestandardowy identyfikator argumentu kontrolera, a nie bezpośrednie nazwane odwołanie do ngModel. Jest to miejsce, w którym konwencja nazywania argumentów „ctrl” lub „controller” zapewnia większą przejrzystość i pozwala uniknąć nieporozumień.
— XML

Dzięki! Cały dzień szukałem fajnego sposobu na zrobienie tego. Niestety, większość innych poprawek polegała na przełączeniu się na selektor dat napisany specjalnie dla kątów, a to było zbyt dużo pracy.
— Josh Mouch

Wypróbowałem odpowiedź zarówno twoją, jak i @SunnyShah, ale jego wydaje się nie działać. Nie pewny dlaczego.
— Josh Mouch

3

W Angular2 + dla wszystkich zainteresowanych:

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

z typem filtrów w DatePipe Angular.


Cholera, utknąłem w starszym AngularJS, nad którym byłem zmuszony pracować i nienawidzę tego! Chciałbym mieć powyższe do pracy.
— Jordan

To tylko drażnienie ludzi i nakłanianie ich do używania Angular2 +. Fuj! AngularJs to prawdziwa bomba. Dlaczego ktoś miałby chcieć takiego prostego rozwiązania.
— Nebulosar

2

Wolę, aby serwer zwracał datę bez modyfikacji, a javascript wykonał masowanie widoku. Mój interfejs API zwraca „MM / DD / RRRR gg: mm: ss” z SQL Server.

Ratunek

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

Kontroler

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

Dyrektywa walidacyjna 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 możesz użyć angularjs ui bootstrap, zapewnia również walidację daty

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



w kontrolerze może określić dowolny format, w jakim chcesz wyświetlać datę jako datefilter

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


nie ma potrzeby implementowania dyrektywy tylko dla pojedynczego pola wejściowego
— P.JAYASRI
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.