如何使用 n- 模型格式化日期?

我有一个输入定义为

<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对象呈现为字符串的方式。

首先,我如何告诉角度显示的日期在 <input>作为类似的 12/22/2009?我似乎不能在 ng-model属性中应用 |filters

其次,一旦我编辑日期,甚至保持它的原始格式,我的其他文本(在 <td>内部)似乎不再应用 |date过滤器; 它突然改变格式,以匹配输入文本框。我如何让它应用的 |date过滤器每次模型的变化?


相关问题:

256988 次浏览

Use custom validation of forms http://docs.angularjs.org/guide/forms Demo: http://plnkr.co/edit/NzeauIDVHlgeb6qF75hX?p=preview

Directive using formaters and parsers and 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() : "";
});
}
};
});

Since you have used datepicker as a class I'm assuming you are using a Jquery datepicker or something similar.

There is a way to do what you are intending without using moment.js at all, purely using just datepicker and angularjs directives.

I've given a example here in this Fiddle

Excerpts from the fiddle here:

  1. Datepicker has a different format and angularjs format is different, need to find the appropriate match so that date is preselected in the control and is also populated in the input field while the ng-model is bound. The below format is equivalent to 'mediumDate' format of AngularJS.

    $(element).find(".datepicker")
    .datepicker({
    dateFormat: 'M d, yy'
    });
    
  2. The date input directive needs to have an interim string variable to represent the human readable form of date.

  3. Refreshing across different sections of page should happen via events, like $broadcast and $on.

  4. Using filter to represent date in human readable form is possible in ng-model as well but with a temporary model variable.

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

I've created a simple directive to enable standard input[type="date"] form elements to work correctly with AngularJS ~1.2.16.

Look here: https://github.com/betsol/angular-input-date

And here's the demo: http://jsfiddle.net/F2LcY/1/

I use the following directive that makes me and most users very happy! It uses moment for parsing and formatting. It looks a little bit like the one by SunnyShah, mentioned earlier.

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

In my form i use it like this:

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

This will bind a timestamp (milliseconds since 1970) to doc.begin and doc.end.

Angularjs ui bootstrap you can use angularjs ui bootstrap, it provides date validation also

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



in controller can specify whatever format you want to display the date as datefilter

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

Here is very handy directive angular-datetime. You can use it like this:

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

It also add mask to your input and perform validation.

I prefer to have the server return the date without modification, and have javascript do the view massaging. My API returns "MM/DD/YYYY hh:mm:ss" from SQL Server.

Resource

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

myDate Validation Directive

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>

I'm using jquery datepicker to select date. My directive read date and convert it to json date format (in milliseconds) store in ng-model data while display formatted date.and reverse if ng-model have json date (in millisecond) my formatter display in my format as jquery datepicker.

Html Code:

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

Angular Directive:

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


}
};
});

In Angular2+ for anyone interested:

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

with type of filters in DatePipe Angular.