How to work whith md-datepicker and moment? - angularjs

In my application i use $scope variables of momemt type.
I'am use md-datepicker from Angular Materialjs for change dates variables at ng-model.
md-datepicker work only with Date type, which I can convert from moment, but after change data by md-datepicker $scope variables change type from Moment to Date.
How to convert result md-datepicker Date type back to moment type?
This is need for use it in other functions which use moment.
<md-datepicker ng-model="momentfrom" md-open-on-focus="true" name="dateFrom" >
</md-datepicker>
The momentfrom variable after work with md-datepicker change type to Date, which need convert to moment.
app.config(['$mdDateLocaleProvider', function ($mdDateLocaleProvider) {
$mdDateLocaleProvider.parseDate = function(dateString) {
var m = moment(dateString, ["DD.MM.YYYY"],true);
return m.isValid() ? m.toDate() : new Date(NaN);
};
$mdDateLocaleProvider.formatDate = function (date) {
return date ? moment(date).format('DD.MM.YYYY') : '';
};
}]);

Your formatting for moment is wrong. Use this in the formatDate function:
return moment(date).format('YYYY-MM-DD');
if you want to set the date to be null on load, then use change the return to this:
return date ? moment(date).format('YYYY-MM-DD') : '';
Refer to the AngularJS Material docs for further information on $mdDateLocaleProvider functionalities.

Related

Angular date filter converter, but date is always converted to UTC

My filter:
.filter('emedicineDateTimeFormat', function ($filter) {
return function (input) {
if (input == null) { return ""; }
var date = $filter('date')(new Date(input), 'dd.MM.yyyy hh:mm:ss');
return date.toUpperCase();
};
});
if Input is: 2017-01-04T14:30:00
then output is 04.01.2017 03:15:00
and not 04.01.2017 14:15:00
Why?
If you want get 24-hours time use upper-cased H. An example is here.
'dd.MM.yyyy HH:mm:ss'
Are you sure that you didn't misspell in output and expected result?
Do you live in UTC+01:00 timezone?
By default AngularJS uses browser timezone. If you want use UTC you should pass the 3rd argument to date filter 'UTC'. Look here.

Is there a way for comparing dates on Valdr?

I'm using Valdr on my project and I need to validate that a date input "startDate" is before another date input "endDate".
<input id="startDate" name="startDate" type="text" ng-model="project.startDate"/>
<input id="endDate" name="endDate" type="text" ng-model="project.endDate"/>
I know that, without Valdr, this problem can be solved using a custom directive, as shown here: Directive for comparing two dates
I found a little unclear how to create a custom validator on Valdr that uses the values of other fields.
The answer is short but dissatisfactory: valdr does currently not support this. There is an open feature request on GitHub, though.
Until the feature gets implemented in valdr, you can use your own validator directive and kind of make it talk to valdr. The directive can require a 'form' and can get the names of the date models you want to compare. Then you do your logic to compare the two values and set the validity of the appropriate 'ngModelController'. Since you need to provide an error when setting the validity to that model, the error name will be your connection with valdr.
After that, you just only need to map the error in the 'valdrMessage' service:
.run(function (valdrMessage) {
valdrMessage.angularMessagesEnabled = true;
valdrMessage.addMessages({
'date': 'Invalid date!'
});
});
Valdr will show the message bellow the invalid field as usual.
Actually you can solve this through a custom validator, which can get another field and compare the values with each other. The code below is using the valdr-bean-validation for serverside generation of valodation.json.
If you want to use it without this, just look into the JS code and add the validator in your validation.json manually.
Java Annotation (serverside declaration of the valdr validator):
package validation;
#Documented
#Retention(RetentionPolicy.RUNTIME)
#Target({ ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR,
ElementType.PARAMETER, ElementType.ANNOTATION_TYPE })
public #interface DateFormat {
String message();
Class[] groups() default { };
String beforeFieldName();
}
Java Bean (usage of the annotation, this class has to be used in the generation of validation.json):
package pojo;
import validation.DateFormat;
public class RegistrationPojo implements BasePojo {
#NotNull(message = "message.date1.required")
private Date date1;
#NotNull(message = "message.date2.required")
#DateFormat(message = "message.date2.date", beforeFieldName = "date1")
private Date date2;
}
JS (implementation of the custom validator and registering it in valdr):
module.factory('validation.DateFormat', [
function () {
return {
name: 'validation.DateFormat',
validate: function (value, constraint) {
var minOk = true;
var maxOk = true;
var format = false; // constraint.pattern is mandatory
//do not validate for required here, if date is null, date will return true (valid)
console.log("my date validator called");
console.log(" beforeFieldName: " + constraint.beforeFieldName);
var field = document.querySelector('[name="' + constraint.beforeFieldName + '"]');
console.log("field value: " + (field ? field.value : "null"));
return (!field || value > field.value);
}
};
}]);
module.config([
"valdrProvider",
function(valdrProvider) {
valdrProvider.addValidator('validation.DateFormat');
}]);
You could go with this solution:
Have a bool value calculated upon changes in any of the date fields - a value indicating if the validation rule is met
Create a simple custom validator to check if that value is true or not
Register your validator and add a constraint for that calculated value
Place a hidden input for that calculated value anywhere you like your validation message to appear

Can't set datepicker date from controller in AngularJS

I am trying to create an AngularJS datepicker on the push of a button. I am using this bootstrap-ui control. The control works (pops up on the click of a button, and I can select a date), but I can't seem to set the initial date back from the scope (so that when it is first opened, the designated date is already selected).
The error I get in the Chrome console is:
Datepicker directive: "ng-model" value must be a Date object, a number of milliseconds since 01.01.1970 or a string representing an RFC2822 or ISO 8601 date.
jade:
button(type="button" ng-model="date.from" btn-radio="'From'" ng-click="date.openFromPopup($event);" show-weeks="false" show-button-bar="false" datepicker-popup = "date.format" is-open = "date.fromOpened" min = "date.minDate" max = "date.today") From
Since I have a watch on $scope.date.from, I can confirm that the selected date is correct, but I can never set it from the controller. Any ideas?
AngularJS controller:
$scope.date = {};
$scope.date.format = "yyyy/MM/dd";
$scope.date.opened = false;
$scope.date.from = new Date();
$scope.date.today = new Date();
$scope.date.minDate = null;
$scope.date.fromOpened = false;
$scope.$watch('date.from', function(v) {
if(v){
alert(v);
}
});
In the example on the angular-ui page, it says to use it like this...
$scope.from = function() {
$scope.dt = new Date();
};
$scope.from();
Does that work?

Set an AngularJS date filter format to be used by all references to the date filter?

Rather that having to define a custom format for each call to the date filter, is there a way to globally define a default format (other than 'medium')?
I would like to have the format set in one file rather than all over the place in my code (the date format may end up being changed in the future and a modification in one file would be much nicer than having to make changes in many files).
This is what I am doing now (defining date format each time):
{{systemTime | date:'dd MMMM # HH:mm:ss'}}
{{modifiedTime | date:'dd MMMM # HH:mm:ss'}}
{{getShippedTime() | date:'dd MMMM # HH:mm:ss'}}
etc.
I was thinking of creating a custom filter (let's call it myDate), which would act as a wrapper and then pass off the date string to the Angular date filter with my custom format, so then my code could just look like this:
{{systemTime | myDate}}
{{modifiedTime | myDate}}
{{getShippedTime() | myDate}}
etc.
However, I can't figure out how to make the myDate filter point to the Angular date filter.
Thanks for your help.
Based on some more research and then considering the comment by moderndegree, I have found that the following myDate filter will work:
.filter('myDate', function($filter) {
var angularDateFilter = $filter('date');
return function(theDate) {
return angularDateFilter(theDate, 'dd MMMM # HH:mm:ss');
}
});
Try this
angular.module('yourmodule').filter('myDate', function($filter)
{
return function(input)
{
if(input == null){ return ""; }
var _date = $filter('date')(new Date(input), 'dd MMMM # HH:mm:ss');
return _date.toUpperCase();
};
});
Html
{{systemTime | myDate}}
Date filtering and formatting in Angular js.
Use a decorator,
It's not what you explicitly asked for, use a decorator. it's built in angular and designed to patch services, directives, filters etc ...
in your case, if the date filter is not provided, you should use your custom date format.
app.config(function ($provide) {
$provide.decorator('dateFilter', function ($delegate) {
return function () {
// Check if the date format argument is not provided
if (!arguments[1]) {
arguments[1] = 'dd MMMM # HH:mm:ss';
}
var value = $delegate.apply(null, arguments);
return value;
};
})
});
The format defaults to mediumDate if none is provided. There is nothing built in to have it default to something else.
https://github.com/angular/angular.js/blob/master/src/ng/filter/filters.js#L382
In case you are working with .aspx pages and have the date format stored in a configuration file...
From the .aspx that injects your Angular page, set a global variable with the web.config date format
var _settingsDateFormat = '<%=appSettings.DateFormat%>';
Set a global filter to be used through your app
yourModule.filter('myDateFormat', function ($filter) {
return function (input) {
if (input == null) { return ""; }
var formattedDate = $filter('date')(new Date(input), _settingsDateFormat);
return formattedDate;
};
});
Just add the custom filter to your dates
Effective {{row.StartDate|myDateFormat}} - {{row.StopDate|myDateFormat}}

angularjs date filter not formatting my json value

I have a service that returns json like so:
"Results":[{"Id":"1","SomeDate":"2/19/2013 10:34:04 PM"}
When i try to format using binding, it doesnt work - it just displays the string above:
{{values.SomeDate| date:'mediumTime' }}
However, it works if i just pass in this format:
{{ '1997-03-01T00:00:00+01:00' | date:'mediumTime'}}
What is the best way to fix this?
As mentioned in the comments by charlietfl, a clean option would be to update the service to return a date format already compatible with the built-in angular filters.
However, if this is not possible, you could set up a custom filter to parse your dates.
A (very small) library that I recommend is Moment.js:
http://momentjs.com/
The following is an example blog post on how to wrap Moment.js in a custom angular filter:
http://www.34m0.com/2012/07/angularjs-user-friendly-date-display.html
angular.module('myModule').
filter('fromNow', function() {
return function(dateString) {
return moment(new Date(dateString)).fromNow()
};
});
This would be used like:
{{ reply.createdDate | fromNow }}
You can place this in your controller:
$scope.toJsDate = function(str){
if(!str)return null;
return new Date(str);
}
and then:
{{toJsDate(values.SomeDate)| date:'mediumTime' }}
I would second #AlexOsborn's suggestion to use moment.js to create a custom filter because moment.js can parse the string containing the date. In my implementation of the filter, I also delegate date formatting to moment.js because I feel moment.js' date formatting feature is more comprehensive than angular.js':
angular
.module("YourModuleNameHere")
.filter("formatdate", [function () {
var result = function (date, formatstring) {
if(formatstring === null) {
formatstring = "DD MMM YYYY";
}
return moment(date).format(formatstring);
}
return result;
}]);
And you use it just like you'd use angular.js date filter (but to format the date you'd use moment.js formatting codes):
<p>Today is {{moment() | formatdate}}</p>
<p>Another date: {{values.SomeDate | formatdate:"ddd D MMM YYYY"}}</p>

Resources