23

I have an Angular 2 application. A service is requests data from an api that returns the results like the following:

{
    "data":[
        {"id":1,"timestamp":"2016-04-17T19:52:53.4510935+01:00","sourceDatabaseServer":"127.0.0.1","sourceDatabaseName":"Database1","targetDatabaseServer":"192.168.99.101","targetDatabaseName":"Database2"},
        {"id":2,"timestamp":"2016-04-17T19:52:53.4510935+01:00","sourceDatabaseServer":"127.0.0.2","sourceDatabaseName":"Database3","targetDatabaseServer":"192.168.99.102","targetDatabaseName":"Database4"},
        {"id":3,"timestamp":"2016-04-17T19:52:53.4510935+01:00","sourceDatabaseServer":"127.0.0.3","sourceDatabaseName":"Database5","targetDatabaseServer":"192.168.99.103","targetDatabaseName":"Database6"}
    ]
}

My Angular 2 service looks like this (I've cut the error handling for brevity as we're on the happy path here):

getList() : Observable<SomeModel[]> {
    return this._http.get(this._getListUrl).map(this.extractData);
}

 private extractData(res: Response) {
    return res.json().data || {};
}

and my component like this:

results: SomeModel[];
errorMessage: string;
ngOnInit() {
    this._someService.getList()
        .subscribe(
        results => this.results = results, 
        error => this.errorMessage = <any>error);
}

and my model like this:

export class SomeModel {

    constructor(
        public id: number,
        public timestamp: Date,
        public sourceDatabaseServer: string,
        public sourceDatabaseName: string,
        public targetDatabaseServer: string,
        public targetDatabaseName: string
    ) { }
}

Everything looked like it was working however when I tried to display timestamp using the DatePipe like so {{item.timestamp | date:'short'}} the application blows up with the following error message:

Invalid argument '2016-04-17T19:40:38.2424240+01:00' for pipe 'DatePipe' in [{{result.timestamp | date:'short'}}

After some investigation I believe that timestamp is not actually being converted to the Date type but is instead just being set a string. I'm guessing this is becuase the Date type isn't known at the time Response.json() is called? or am I missing something else entirely? Is there a fix or work around for this?

2
  • 1
    When you do a .json() that will not transform a string (even if it's in some date format) to an actual date object. It'll keep being a string. so you need to do new Date(herePassTheString)
    – arg20
    Commented Apr 17, 2016 at 19:32
  • 1
    If you are only displaying it, the DatePipe in Angular 2 can now use the ISO string format. angular.io/docs/ts/latest/api/common/index/DatePipe-pipe.html I do not know if this has always been the case, but it is now. ;)
    – Derrick
    Commented Feb 8, 2017 at 13:41

4 Answers 4

24

I would map the string field to a date one:

getList() : Observable<SomeModel[]> {
  return this._http.get(this._getListUrl).map(this.extractData);
}

private extractData(res: Response) {
  var data = res.json().data || [];
  data.forEach((d) => {
    d.timestamp = new Date(d.timestamp);
  });
  return data;
}
2
  • Yep, best approach... everything after that is in alignment then! And here's for an alternative format :-), d.timestamp = new Date(parseInt(d.timestamp.substr(6)));
    – Tim Harker
    Commented Apr 5, 2017 at 18:49
  • 1
    Why do I get an error on this line: var data = res.json().data || []; when I try to use this code? "Property data does not exist on type Promise<any>"
    – Mohaaron
    Commented Jan 3, 2018 at 0:29
6

The date pipe only accepts Date values not string values.

See How to get Date object from json Response in typescript for how to convert dates in JSON.

Alternatively you can create your own string-to-date conversion pipe

@Pipe({name: 'toDate'})
export class StringToDate implements PipeTransform {
  transform(value, [exponent]) : number {
    if(value) {
      return new Date(value);
    }
  }
}

and then use it like

{{item.timestamp |toDate | date:'short'}}

Hint: don't forget to add the pipe to pipes: [StringToDate] on the @Component(...) decorater where you want to use it.

See also

4
3

JSON does not provide any date specification, so it is entirely up to how it is serialized/deserialized.

You could use reviver parameter of JSON.parse:

this._http.get(this._getListUrl).map(res => JSON.parse(res.text(), this.reviver));

reviver(key, value):any
{
    if('timestamp' === key){
        //you can use any de-serialization algorithm here
        return new Date(value);
    }
    return value;
}
3

Try out my example if its work for you. And here is the docs for Date and Pipe.

<span>Date : {{announcement.createdAt | date:'EEE, d MMM,y'}}</span>
<span>Time : {{announcement.createdAt | date:'shortTime'}}</span>

Output :

Date : Tue, 20 Dec,2016    
Time :  2:22 PM

Not the answer you're looking for? Browse other questions tagged or ask your own question.