core
core copied to clipboard
Translate pipe used with a Date parameter is not triggered when the parameter changes
Angular 8 ngx-translate/core: 11.0.1 ngx-translate-messageformat-compiler: 4.5.0
We are using ngx-translate-messageformat-compiler along with ngx-translate to support translation of Date
with accurate date format according to the current lang (among other things).
So we have some cases where we give just Date
parameters to the translate
pipe.
The translate
pipe works fine the first time it is triggered but when the value of one parameter changes, the pipe does not update the value displayed anymore.
Here's an exemple :
html
<div>{{ 'test' | translate:param }}</div>
json
{
"test": "This is a date : {myDate, date, short}"
}
component
public param = {myDate: new Date()};
change(newDate: Date) {
this.param = { myDate: newDate };
}
As I said the date displayed in the html is not updated when the value of this.param
changes as the method change
is called with a different Date
.
I'm pretty sure it's because of the start of the transform
method of TranslatePipe
:
translate.pipe.ts
transform(query: string, ...args: any[]): any {
if (!query || query.length === 0) {
return query;
}
// if we ask another time for the same key, return the last value
if (equals(query, this.lastKey) && equals(args, this.lastParams)) {
return this.value;
}
The problem is the equal
fonction (see here) which returns true for 2 different Date
objects.
To force the pipe to see a difference between args
and this.lastParams
I can modify the code like this :
component
public param = {myDate: new Date(), myDateAsString: new Date().toISOString()};
change(newDate: Date) {
this.param = { myDate: newDate, myDateAsString: myDate.toISOString() };
}
By doing this, the equals
function see a difference between both param values (args
and this.lastParams
), because the comparison of the string values return false, and now the pipe works as expected.
But this is an ugly workaround.
The equals function should return false for 2 different Date objects in the first place.
i can confirm this still exists in version 15.x.
The issue arises from the fact that the equals
method compares Date
objects as objects, and the keySet
only exists of fp_incr
. This is a function pointer which is the same for any two Date objects.
keySet = Object.create(null);
for (key in o1) { // -> ['fp_incr', undefined]
if (!equals(o1[key], o2[key])) {
return false;
}
keySet[key] = true;
}