Angular 2 Дата десериализации

У меня есть приложение Angular 2. Служба запрашивает данные из api, которые возвращают результаты следующим образом:

{
    "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"}
    ]
}

Моя служба Angular 2 выглядит так (я сократил обработку ошибок для краткости, поскольку мы находимся на счастливом пути здесь):

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

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

и мой компонент следующим образом:

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

и моя модель:

export class SomeModel {

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

Все выглядело так, как будто оно работало, но когда я пытался отображать временную метку с помощью DatePipe, так что {{item.timestamp | date:'short'}} приложение взорвалось со следующим сообщением об ошибке:

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

После некоторого исследования я считаю, что временная метка фактически не преобразуется в тип Date, а вместо этого устанавливается только string. Я предполагаю, что это потому, что тип Date не известен в то время, когда вызывается Response.json()? или я вообще что-то пропустил? Есть ли для этого исправление или работа?

Ответы

Ответ 1

Я бы сопоставил поле строки с датой:

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

В трубке date принимаются значения date не строковые значения.

Смотрите Как получить объект Date из json Response в typescript для того, как конвертировать даты в JSON.

В качестве альтернативы вы можете создать свой собственный строковый протокол преобразования

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

а затем используйте его как

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

Подсказка: не забудьте добавить трубу в pipes: [StringToDate] на декортере @Component(...), где вы хотите ее использовать.

См. также

Ответ 3

Попробуйте мой пример, если его работа для вас. И вот документы для Date и Pipe.

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

Выход:

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

Ответ 4

JSON не предоставляет спецификацию даты, поэтому полностью зависит от того, как она сериализована/десериализована.

Вы можете использовать reviver параметр 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;
}