Bagaimana memformat tanggal menggunakan ng-model?

93

Saya memiliki masukan yang didefinisikan sebagai

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

Yang dicurangi untuk ditampilkan di tempat lain pada halaman:

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

Ketika halaman memuat tanggal lahir dengan baik diformat sebagai sesuatu seperti Dec 22, 2009. Namun, ketika saya melihat ke dalam saya, <input>itu ditunjukkan seperti Tue Dec 22 2009 00:00:00 GMT-0800 (Pacific Standard Time)yang saya kira adalah bagaimana JS menjadikan Dateobjek sebagai string.

Pertama, bagaimana cara memberi tahu Angular untuk menunjukkan tanggal di <input>sebagai sesuatu seperti 12/22/2009? Saya tidak bisa menerapkan |filtersdi dalam ng-modelatribut.

Kedua, segera setelah saya mengedit tanggal, bahkan menyimpannya dalam format aslinya, teks saya yang lain (di dalam <td>) tampaknya tidak |datelagi menerapkan filter; itu tiba-tiba mengubah format agar sesuai dengan input textbox. Bagaimana cara menerapkan |datefilter setiap kali model berubah?


Pertanyaan-pertanyaan Terkait:

mpen
sumber
Saya juga punya masalah itu, tapi datang dengan solusi yang lebih sederhana menggunakan Date()fungsi js standar : $scope.departDate = new Date(); $scope.departTime = $scope.departDate.toTimeString().slice(0, 5);Dan tidak perlu filter lain atau solusi rumit di AngularJS IMO.
boldnik

Jawaban:

71

Gunakan validasi kustom dari formulir http://docs.angularjs.org/guide/forms Demo: http://plnkr.co/edit/NzeauIDVHlgeb6qF75hX?p=preview

Direktif menggunakan formaters dan parser dan 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() : "";
            });
        }
    };
});
SunnyShah
sumber
4
Saya ingin membuat contoh kecil dari formater dan parser, Terima kasih atas pertanyaan Anda hari ini, saya mendapat alasan untuk melakukannya.
SunnyShah
1
@ Mark, Memperbaiki masalah Nan di biola kedua. ;)
SunnyShah
1
Pendekatan kedua dihapus. Itu terlalu buggy.
SunnyShah
1
Anda dapat menggunakan perintah on-change untuk melakukan perbaikan lebih lanjut. stackoverflow.com/questions/14477904/…
SunnyShah
7
@SunnyShah - barang bagus, sangat membantu, terima kasih banyak. Saya bertanya-tanya mengapa Anda memiliki var dateFormat = attrs.moMediumDate;dan tidak var dateFormat = attrs.moDateInput;moMediumDate sepertinya tidak disetel di mana pun jadi jika input tidak dibuat secara dinamis, format awal tidak pernah dipilih.
Toxaq
37

Berikut adalah direktif angular-datetime yang sangat berguna . Anda bisa menggunakannya seperti ini:

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

Itu juga menambahkan mask ke input Anda dan melakukan validasi.

Sergei Svekolnikov
sumber
1
Saya menggunakan arahan ini juga, terima kasih. Jika Anda menggunakannya dengan jQuery UI Datepicker, Anda harus memastikan format yang ditentukan dalam nilai datetime="<format>"atribut cocok dengan format yang ditentukan dalam opsi Datepicker dateFormat.
tylerwal
1
Saya bertanya-tanya bagaimana mungkin ada solusi sempurna di sini dengan hanya beberapa suara. Begitu banyak untuk kencan, dan Anda dapat menyelesaikannya di sini, sekarang juga! Terima kasih Bung.
C0ZEN
2
Saya yakin lebih banyak orang akan memilih ini, jika dokumentasinya ditingkatkan untuk membuatnya lebih mudah untuk dimasukkan dalam aplikasi sudut yang ada.
Joel Hansen
8

Saya telah membuat arahan sederhana untuk mengaktifkan input[type="date"]elemen formulir standar agar berfungsi dengan benar dengan AngularJS ~ 1.2.16.

Lihat di sini: https://github.com/betsol/angular-input-date

Dan inilah demonya: http://jsfiddle.net/F2LcY/1/

Slava Fomin II
sumber
Hai @ Lorenzo, apa maksudmu? Bisakah Anda menjelaskan lebih lanjut?
Slava Fomin II
Hari bulan tahun dalam bahasa Prancis seperti Lun Mar Mer untuk Sen Sel, Wen
Merlin
@ Lorenzo, saya tidak yakin saya undetstand. Arahan tidak ada hubungannya dengan pelokalan. Mungkin fungsi pemformatan yang Anda gunakan mengambil pengaturan lokal dari browser / sistem Anda. Jika Anda memberikan contoh, saya akan dapat membantu (jsfiddle).
Slava Fomin II
1
hanya mendukung chrome, sangat buruk.
GeminiKuning
Tujuan dari arahan ini adalah untuk mendukung semua platform. Jika Anda memiliki masalah dengan itu mengapa Anda tidak membuat masalah di repo GitHub? Saya selalu menanggapi semua masalah.
Slava Fomin II
7

Saya menggunakan jquery datepicker untuk memilih tanggal. Tanggal baca direktif saya dan mengubahnya menjadi format tanggal json (dalam milidetik) disimpan dalam ng-modeldata sambil menampilkan tanggal yang diformat. Dan sebaliknya jika ng-model memiliki tanggal json (dalam milidetik) tampilan formatter saya dalam format saya sebagai jquery datepicker.

Kode Html:

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

Arahan Sudut:

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

        }
    };
});
Amit Bhandari
sumber
Ya ampun!! Terima kasih banyak !! Saya benar-benar telah mencari dua hari untuk sesuatu seperti jawaban ini, tetapi tidak dapat menemukannya! Kamu keren!
Michael Rentmeister
Fantastis. Saya telah mencari sesuatu seperti ini untuk sementara waktu. Saya menggunakan materializecss untuk solusi saya. Jika seseorang tersandung pada ini dan perlu mengubah arahan ini untuk terwujud, tukar saja element.datepickerdenganelement.pickadate
IWI
7

Karena Anda telah menggunakan datepicker sebagai kelas, saya berasumsi Anda menggunakan datepicker Jquery atau yang serupa.

Ada cara untuk melakukan apa yang Anda inginkan tanpa menggunakan moment.js sama sekali, hanya menggunakan arahan datepicker dan angularjs.

Saya telah memberikan contoh di sini di Fiddle ini

Kutipan dari biola di sini:

  1. Datepicker memiliki format yang berbeda dan format angularjs berbeda, perlu menemukan kecocokan yang sesuai sehingga tanggal dipilih sebelumnya dalam kontrol dan juga diisi di bidang input saat model-ng terikat. Format di bawah ini setara dengan 'mediumDate'format AngularJS.

    $(element).find(".datepicker")
              .datepicker({
                 dateFormat: 'M d, yy'
              }); 
  2. Direktif input tanggal harus memiliki variabel string sementara untuk mewakili bentuk tanggal yang dapat dibaca manusia.

  3. Menyegarkan di berbagai bagian laman harus dilakukan melalui acara, seperti $broadcastdan $on.

  4. Menggunakan filter untuk merepresentasikan tanggal dalam bentuk yang dapat dibaca manusia juga dimungkinkan dalam ng-model tetapi dengan variabel model sementara.

    $scope.dateValString = $filter('date')($scope.dateVal, 'mediumDate');
Praveenram Balachandar
sumber
6

Saya menggunakan petunjuk berikut yang membuat saya dan sebagian besar pengguna sangat senang! Ini menggunakan momen untuk parsing dan pemformatan. Ini terlihat sedikit mirip dengan yang oleh SunnyShah, yang disebutkan sebelumnya.

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

Dalam formulir saya, saya menggunakannya seperti ini:

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

Ini akan mengikat stempel waktu (milidetik sejak 1970) ke doc.begindan doc.end.

Elmer
sumber
1
Sangat mudah untuk mengabaikan fakta bahwa, di dalam fungsi link ini, ngModeladalah pengenal kustom Anda untuk argumen controller, bukan referensi langsung bernama ke ngModel. Ini adalah tempat di mana konvensi penamaan arg 'ctrl' atau 'controller' membuat segalanya lebih jelas dan menghindari kebingungan.
XML
Terima kasih! Sepanjang hari aku mencari cara yang bagus untuk melakukan ini. Sayangnya, sebagian besar perbaikan lain melibatkan peralihan ke datepicker yang ditulis khusus untuk sudut, dan itu terlalu banyak pekerjaan.
Josh Mouch
Saya mencoba jawaban Anda dan @SunnyShah, tetapi sepertinya tidak berhasil. Tidak yakin kenapa.
Josh Mouch
3

Di Angular2 + untuk siapa pun yang tertarik:

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

dengan jenis filter di DatePipe Angular.

Quan VO
sumber
Sial, saya terjebak dalam AngularJS warisan yang terpaksa saya kerjakan, dan saya membencinya! Seandainya saya memiliki yang di atas untuk dikerjakan.
Yordania
Ini hanya menggoda orang dan mengelabui mereka agar menggunakan Angular2 +. Yuck! AngularJs benar-benar bomnya. Mengapa ada orang yang menginginkan solusi sederhana seperti ini.
Nebulosar
2

Saya lebih suka server mengembalikan tanggal tanpa modifikasi, dan meminta javascript melakukan tampilan memijat. API saya mengembalikan "MM / DD / YYYY hh: mm: ss" dari SQL Server.

Sumber

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

Petunjuk Validasi 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>
meffect
sumber
1

Angularjs ui bootstrap Anda dapat menggunakan angularjs ui bootstrap, ini juga menyediakan validasi tanggal

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



dalam kontroler dapat menentukan format apa pun yang Anda inginkan untuk menampilkan tanggal sebagai datefilter

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

P.JAYASRI
sumber
Anda tidak perlu mengimplementasikan direktif hanya untuk satu input field
P.JAYASRI