Як відформатувати дату за допомогою ng-моделі?


93

У мене вхід визначено як

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

Що встановлено для відображення в іншому місці на сторінці:

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

Коли сторінка завантажує дату народження, вона добре відформатована як щось подібне Dec 22, 2009. Однак, коли я заглядаю всередину свого, <input>це відображається так, як Tue Dec 22 2009 00:00:00 GMT-0800 (Pacific Standard Time)я гадаю, як JS представляє Dateоб'єкти як рядки.

По-перше, як я можу сказати Angular показати дату <input>як щось подібне 12/22/2009? Я, здається, не застосовується |filtersвсередині ng-modelатрибута.

По-друге, як тільки я редагую дату, навіть зберігаючи її в оригінальному форматі, мій інший текст (всередині <td>), схоже, вже не застосовує |dateфільтр; він раптово змінює формати, щоб відповідати формату вхідного текстового поля. Як змусити його застосовувати |dateфільтр щоразу, коли модель змінюється?


Пов’язані запитання:


У мене також була проблема з цим, але я запропонував більш просте рішення з використанням стандартних Date()функцій js : $scope.departDate = new Date(); $scope.departTime = $scope.departDate.toTimeString().slice(0, 5);І немає необхідності в інших фільтрах чи хитромудріших обхідних шляхах в IMO AngularJS.
болдник

Відповіді:


71

Використовуйте спеціальну перевірку форм http://docs.angularjs.org/guide/forms Demo: http://plnkr.co/edit/NzeauIDVHlgeb6qF75hX?p=preview

Директива, що використовує формати та парсери та 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
Я хотів створити невеликий приклад форматера та парсера. Завдяки вашому сьогоднішньому питанню я отримав привід зробити це.
SunnyShah

1
@Mark, виправлено випуск Nan у другій скрипці. ;)
SunnyShah

1
Видалений другий підхід. Це було занадто глючно.
SunnyShah

1
Ви можете використовувати директиву про зміну, щоб зробити подальші вдосконалення. stackoverflow.com/questions/14477904 / ...
SunnyShah

7
@SunnyShah - чудові речі, дуже корисні, дуже дякую. Мені було цікаво, чому у вас, var dateFormat = attrs.moMediumDate;а не var dateFormat = attrs.moDateInput;moMediumDate, здається, ніде не встановлено, тому якщо входи не створюються динамічно, початковий формат ніколи не вибирається.
toxaq

37

Ось дуже зручна директива щодо кутової дати . Ви можете використовувати його так:

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

Він також додає маску до вашого вводу та виконує перевірку.


1
Я також використав цю директиву, дякую. Якщо ви використовуєте його з jQuery UI Datepicker, ви повинні переконатися, що формат, визначений у datetime="<format>"значенні атрибута, відповідає формату, визначеному в dateFormatопції Datepicker .
tylerwal

1
Цікаво, як можливо, що тут є ідеальне рішення з лише кількома голосами. Стільки за побаченнями, і ви можете вирішити їх прямо тут, прямо зараз! Дякую, чувак.
C0ZEN

2
Я впевнений, що більше людей проголосували б за це, якби документацію було покращено, щоб полегшити її включення в існуючий кутовий додаток.
Джоель Хансен

8

Я створив просту директиву, щоб стандартні input[type="date"]елементи форми працювали правильно з AngularJS ~ 1.2.16.

Подивіться тут: https://github.com/betsol/angular-input-date

А ось демонстрація: http://jsfiddle.net/F2LcY/1/


Гей, @Lorenzo, що ти маєш на увазі? Не могли б ви детальніше розглянути?
Слава Фомін II

День місяця в році є французькою мовою, як Лун Мар Мер для Пн Вт, Вень
Мерлін

@Lorenzo Я не впевнений, що розумію. Директива не має нічого спільного з локалізацією. Можливо, функція форматування, яку ви використовуєте, приймає налаштування мови у вашому браузері / системі. Якщо ви подасте приклад, я зможу допомогти (jsfiddle).
Слава Фомін II

1
просто підтримую хром, так погано.
GeminiYellow

Мета директиви - підтримка всіх платформ. Якщо у вас є проблеми з цим, чому ви не створите проблему на репортажі GitHub? Я завжди відповідаю на всі питання.
Слава Фомін II

7

Для вибору дати я використовую інструмент jquery datepicker. Моя директива читає дату і перетворює її у формат дати json (у мілісекундах) зберігає ng-modelдані, відображаючи відформатовану дату.і зворотним, якщо у ng-моделі є дата json (у мілісекундах), моє форматування відображається у моєму форматі як jquery datepicker.

Код HTML:

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

Кутова директива:

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

        }
    };
});

О Боже!! Велике спасибі sooooo !! Я буквально два дні шукав щось подібне на цю відповідь, але не зміг його знайти! Ти рок!
Майкл Рентмайстер

Фантастичний. Я деякий час шукав щось подібне. Я використовую materializecss для свого рішення. Якщо хто - то stubles на цьому і потреби перетворити цю директиву для матеріалізації, просто вивантажити element.datepickerзelement.pickadate
IWI

7

Оскільки ви використовували datepicker як клас, я припускаю, що ви використовуєте датчик вибору Jquery або щось подібне.

Існує спосіб робити те, що ви маєте намір, не використовуючи момент moment.js, використовуючи лише директиви datepicker і angularjs.

Я наводив приклад тут, у цій скрипці

Уривки з загадки тут:

  1. Datepicker має інший формат, а формат angularjs відрізняється, потрібно знайти відповідний збіг, щоб дата була попередньо вибрана в елементі управління, а також заповнюється у полі введення, поки ng-модель пов'язана. Наведений нижче формат еквівалентний 'mediumDate'формату AngularJS.

    $(element).find(".datepicker")
              .datepicker({
                 dateFormat: 'M d, yy'
              }); 
    
  2. Директива про введення дати повинна мати проміжну змінну рядка для відображення читаної людиною форми дати.

  3. Оновлення в різних розділах сторінки має відбуватися через події, як-от $broadcastі $on.

  4. Використання фільтра для представлення дати у читаному для людини вигляді можливо і в ng-моделі, але з тимчасовою змінною моделі.

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

6

Я використовую наступну директиву, яка робить мене і більшість користувачів дуже щасливими! Він використовує момент для розбору та форматування. Це трохи схоже на той, про який згадував раніше 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

У своїй формі я використовую це так:

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

Це пов'язує часову позначку (мілісекунди з 1970 року) до doc.beginта doc.end.


1
Легко не помітити той факт, що всередині цієї функції посилань - ngModelце ваш власний ідентифікатор для аргументу контролера, а не прямий іменний посилання на ngModel. Це місце, де домовленість називати цей аргумент "ctrl" або "контролер" забезпечує чіткіші речі і уникає плутанини.
XML

Дякую! Я цілий день шукав приємного способу зробити це. На жаль, більшість інших виправлень включали перехід на панель вибору дати, написану спеціально для кутових, і це було занадто багато роботи.
Джош Мауч

Я спробував і вашу відповідь, і відповідь @SunnyShah, але його, схоже, не вийшло. Не знаю, чому.
Джош Муш

3

У програмі Angular2 + для всіх, хто цікавиться:

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

з типом фільтрів у DatePipe Angular.


Данг, я застряг у спадщині AngularJS, над якою мене змусили працювати, і ненавиджу! Бажаю, щоб у мене було вище, з чим працювати.
Йорданія

Це просто дражнить людей і обманює їх використовувати Angular2 +. Гидота! AngularJs - це абсолютно бомба. Чому хтось хоче такого простого рішення.
Небулосар

2

Я вважаю за краще, щоб сервер повертав дату без змін, і щоб JavaScript масував перегляд. Мій API повертає "MM / DD / РРРР год. Год. Мм: мм: сс" з SQL Server.

Ресурс

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

Контролер

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

Директива про затвердження 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 Ви можете використовувати angularjs ui bootstrap, він також забезпечує перевірку дати

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



в контролері можна вказати, у якому форматі ви хочете відобразити дату як datefilter

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


вам не потрібно реалізовувати директиву лише для одного поля введення
P.JAYASRI
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.