How to customise the "invalid date" in moment - javascript

Im trying to customise the error message of moment when a date is invalid, so I don't get "Invalid Date" each time.
For exemple one time I would like the result to be blank if the date is not correct, an other time I want it to be "This date is not correct"
Is there any way to do so ?
I searched everywhere and didn't find anything, so far the only way is to change it that way
moment.updateLocale("es", {
invalidDate: "Fecha invalida"
});
But it's just to change the message everywhere. I want to be able to custom it everywhere.
So the only solution I found so far is to use the function
isValid();
And so create a function like
CustomMomentErrorMsg(moment(...), 'my error msg')
and the function can look like this
function CustomMomentErrorMsg(MyDate, errorMessage) {
if (MyDate.IsValid()) {
return MyDate
}
else {
return errorMessage
}
}
or something like
function CustomMomentErrorMsg(MyDate, errorMessage) {
if (MyDate == "Invalid Date") {
return errorMessage }
else {
return MyDate
}
}
Isnt there a way just like
moment(MyDate).format("DD/MM/YYYY").error("This is a custom error message")
Thanks

If you look at moment's source code, you'll see that the error message for an invalid date is part of the locale configuration, and the format() function internally calls the formatMoment() function, which, in turn, checks for validity and returns the global locale configuration for the error message text:
function formatMoment(m, format) {
if (!m.isValid()) {
return m.localeData().invalidDate();
}
// the rest of the code doesn't interest us in your case
}
( those functions can be understood as getters for internal properties ._locale and ._invalidDate which can, but absolutely should not be accessed by the end user as it's considered bad practice - this is why there is this public API available ).
Default (parent) locale configuration is stored in the baseConfig variable:
var baseConfig = {
calendar: defaultCalendar,
longDateFormat: defaultLongDateFormat,
invalidDate: defaultInvalidDate,
...
...
...
meridiemParse: defaultLocaleMeridiemParse,
};
and the default value is set a few lines above like this:
var defaultInvalidDate = 'Invalid date';
As you can see, the error text is not a property of the moment, it's a property of the locale and so can't be different for different moment objects. Unless you're willing to change the locale settings every time you generate a new date, the solution that you provided seems legit and usable!
P.S. I put some related console.log() in this code snippet
// creating an invalid moment
var m = moment.invalid();
// don't use properties that begin with underscore!
console.log(m._isValid);
console.log(m.isValid());
// formatting returns the same result as toString()
// and the general message in the locale data object
console.log(m.format());
console.log(m.toString());
console.log(m.localeData()["_invalidDate"]);
console.log(m.localeData());
<script src="https://momentjs.com/downloads/moment-with-locales.js"></script>

Related

Typescript typecasting fails on run time but ok during build

i have a Typescript class responsible for storing and retrieving any object, its type as well as the date when the object was stored in LocalStorage (code below)
Problem is the "storageDate" property. Though during compile time, TS mentions the type to be "Date" but at runtime its a string. So i can not use for eg toDateString() function on storageDate.
Any idea why this is happening and suggestions on how to write it?
//Class
export interface ILocalStorageReturnValue<T>{
storageDate:Date;
storedObj:T
}
export class LocalStorage<T> implements ILocalStorage<T>
{
constructor(){
if( !window.localStorage)
throw new Error(`[${constants.FrameWorkName}.LocalStorage]:${strings.ErrBrowserNoLclStrg}`)
}
public setItem(key: string, val: T): void{
if(!key || !val )
throw new Error(`[${constants.FrameWorkName}.LocalStorage.setItem]:${strings.ErrMissingKeyValProp}`)
const newObj:ILocalStorageReturnValue<T> = {
storedObj: val,
storageDate: new Date()
}
window.localStorage.setItem(key ,JSON.stringify(newObj))
}
public getItem(key: string): ILocalStorageReturnValue<T> | null{
return JSON.parse( window.localStorage.getItem(key)) ? <ILocalStorageReturnValue<T>>JSON.parse( window.localStorage.getItem(key)):null
}
}
// access
const ls = new LocalStorage<IImage>().getItem(constants.localStorageKey)
ls.storageDate().toDateString() --> throws an error saying toDateString is not a function .
The problem is that your code doesn't ensure the shape of the object is correct when you retrieve it from local storage. JSON doesn't have any concept of dates, but you're returning the result of JSON.parse (without any reviver function) and telling TypeScript that that is a ILocalStorageReturnValue<T>. But it isn't one, because ILocalStorageReturnValue's storageDate is a Date, and JSON.parse (without a reviver function) will never create a Date. You have to do that in your code. The type assertion¹ is incorrect, but TypeScript trusts what you tell it.
Since you're relying on the default handling of dates when you store the item, the storageDate string in local storage will be compatible with new Date, so you could do this:
public getItem(key: string): ILocalStorageReturnValue<T> | null {
const str = window.localStorage.getItem(key);
if (!str) {
return null;
}
const result = JSON.parse(str);
result.storageDate = new Date(result.storageDate);
return result;
}
Playground link
¹ Note that TypeScript doesn't have casting, it has type assertions. A type assertion is purely a compile-time thing. It's you telling TypeScript the type of something that it may not be able to figure out the type of. Type assertions have no effect whatsoever at runtime.

Unable to get new values from external module

I have a date module that returns current date that is set in system:
function getDateFormatAndISODate() {
const dates = require('./resources/getSystemDate').getSystemDate();
return dates;
}
module.exports.getDateFormatAndISODate = getDateFormatAndISODate;
I am requiring it in another file:
import * as isoDateModule from './datastream-get-iso-module';
The issue is the method call is not returning new date values when user changes the date manually from system and call this method again:
isoDateModule.getDateFormatAndISODate(dateVal);
I am using c node addon in my project and I am requiring it like this:
function requireUncached(module) {
delete require.cache[require.resolve(module)];
return require(module);
}
const dates = requireUncached('./resources/getSystemDate').getSystemDate();
But still I get the old date values. Not sure whats missing

Extract TImestamp from the result of a Function

So I have an interface like this:
interface Test {
// ...
created_at: Timestamp;
// ...
}
and I return an object from a function like this:
export const getTest = functions.https.onCall(async (data, context) => {
if (!context.auth) {
return null;
}
let snap = await admin
.firestore()
.collection('test')
.get();
return snap.docs.map(r => ({ // Add id to the output
id: r.id,
...r.data()
})[0];
});
So I should be getting the timestamp object in my application, but this is what I get in the chrome console, when I try to get the object from the function like so:
// Using AngularFireFunctions
let result: Test = await this.fns.httpsCallable<void, Test>('getTest')().toPromise();
This is the whole content of result.created_at:
When I call result.created_at.toDate() I get an ....created_at.toDate is not a function error.
What can I do to change this?
This is what I am stuck with right now:
result.created_at = new Date(result.created_at._seconds * 1000);
It looks like you’re expecting the callable function to retain the data type of the objects returned from it. That’s not quite how it works. The function will serialize the passed objects as JSON, losing all object type information, including the Timestamp type. The Timestamp is being serialized using its internal representation, which is what you’re seeing in the log output. I wouldn’t write code that depends on this, as it's obviously using hidden implementation details.
What you should probably do instead is convert that Timestamp into a normal JavaScript object, and use that in the returned result. Then, on the client side, you will need to write code that understands how you’ve chosen to represent that timestamp. It is extra work, but it insulates the client from knowing those private implementation details.
I suggest putting the seconds and nanoseconds part of the Timestamp into a plain old object, replacing the existing Timestamp field, then converting that object back into a Timestamp on the client using the Timestamp constructor that takes the seconds and nanos components as arguments.

"Attempted to handle event `reloadRecord` on <App.User:ember820:me> while in state root.deleted.saved. "

I tried searching for same kind off issue if asked already but couldn't find exactly.
My problem is:-
I'm calling a function from a .handlebars class with the required parameters but while it is calling the function, at one point where it's calling reload() function, it throws exception.
The code snippet is like:-
saveBookmark: function saveBookmark(name, value, version) {
var self = this;
this.get('user').reload().then(function () {
var bookmarks = self.get('bookmarks') || [];
var newBookmarkId = bookmarks.sortBy('id').getWithDefault('lastObject.id', 0) + 1;
var date = moment().format('YYYY-MM-DD');
bookmarks.push({ key: self.get('key'), version: version, id: newBookmarkId, name: name, value: value, date: date });
self.set('bookmarks', bookmarks);
self.send('savePreferences');
});
},
So, the exact line where it;s throwing error is:-
this.get('user').reload()
However, on browser console, I can find the value of
this.get('user')
Firther, I can not make changes to this function as this is generic and is being used aross several places and working fine.
If you could provide me some idea of occurrence of this issue to resolve would be of much help.
The exception I'm getting is:-
"Attempted to handle event `reloadRecord` on <App.User:ember820:me> while in state root.deleted.saved. "
PS:- I'm new to Ember.js.
That error means your user object (the one you refer to with this.get('user')) is in an invalid state (did it get deleted somewhere else?). And so the code you are writing is complaining that it can't reload a deleted model ...

AngularJS unit testing with jasmine form validity in a watch breaking tests

I'm pulling my hair out trying to work out whats I'm missing and after 5 hours of googling I'm not closer to the answer so this is my last shot.
I have a AngularJS app and in one of the unit tests I'm checking that a controller displays some data after a api call. My problem is I have a watch on that controller that is running some date validation and it is breaking my tests. If I remove the watch the tests pass fine. The error I'm getting from my tests is below:
Result Message: TypeError: 'undefined' is not a function (evaluating '$scope.filterOrdersForm.txtDateFrom.$setValidity('txtDateFromValid', true)')
This is the code my watch is calling:
$scope.checkSearchCriteriaDateValidity = function() {
var dateFrom = moment($scope.searchCriteria.dateFrom);
var dateTo = moment($scope.searchCriteria.dateTo);
// check each date for validity
if (dateFrom.isValid() !== true) {
$scope.filterOrdersForm.txtDateFrom.$setValidity('txtDateFromValid', false);
} else {
$scope.filterOrdersForm.txtDateFrom.$setValidity('txtDateFromValid', true);
}
if (dateTo.isValid() !== true) {
$scope.filterOrdersForm.txtDateTo.$setValidity('txtDateToValid', false);
} else {
$scope.filterOrdersForm.txtDateTo.$setValidity('txtDateToValid', true);
}
// check if both are valid and if so make sure from date is before to date
if (dateFrom.isValid() && dateTo.isValid()) {
if (dateFrom.isAfter(dateTo)) {
$scope.filterOrdersForm.txtDateFrom.$setValidity('fromBeforeTo', false);
} else {
$scope.filterOrdersForm.txtDateFrom.$setValidity('fromBeforeTo', true);
}
}
};
Can some point out what I'm missing. Do I have to do something special with my tests to deal with this situation? Any help would be appreciated.
I hope my answer will be helpful for you. The problem is $setvalidity is a method which was in undefined while executing your method by jasmine script. In order to fix that, you have to create a mock method for set validity before u calling the corresponding method.
Please try the below code in it method,
$scope.filterOrdersForm = {txtDateFrom : {$setValidity: function (var1,var2){ return true }}};
Spyon( $scope.filterOrdersForm.txtDateFrom,"$setValidity");

Categories

Resources