Как я могу обновить дату в формате Angular2 DatePipe?

Пример проблемы: http://plnkr.co/edit/7FeRoyyqDnj

import {Component, NgModule} from '@angular/core'
import {BrowserModule} from '@angular/platform-browser'

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2>{{myDate}}</h2> <!-- THIS UPDATES AS EXPECTED -->
      <h2>{{myDate | date: 'longDate'}}</h2> <!-- THIS DOES NOT -->
      <a (click)="prevMonth()" href="javascript:;">Previous Month</a>
      <a (click)="nextMonth()" href="javascript:;">Next Month</a>
    </div>
  `,
})
export class App {
  myDate: Date;
  constructor() {
    this.myDate = new Date();
  }

  nextMonth() {
    this.myDate.setMonth(this.myDate.getMonth() + 1);
  }

  prevMonth() {
    this.myDate.setMonth(this.myDate.getMonth() - 1);
  }
}

@NgModule({
  imports: [ BrowserModule ],
  declarations: [ App ],
  bootstrap: [ App ]
})
export class AppModule {}

Когда я передаю свою переменную без использования каналов, она обновляется, как и ожидалось. Но копия той же переменной в формате DatePipe не обновляется. Пайп обновляется только для наблюдаемых? Или я могу использовать это со стандартным типом даты и ожидать, что он будет обновляться в реальном времени?

Я не вижу в API DatePipe ничего, что предлагало бы это как ожидаемое поведение, но я сузил его до точки, когда только DatePipe мог бы таким образом влиять на поведение. https://angular.io/docs/ts/latest/api/common/index/DatePipe-pipe.html


person D. Zielinski    schedule 10.11.2016    source источник


Ответы (3)


Это не работает, потому что Angular2 DatePipe с отслеживанием состояния (для свойства pure установлено значение true в функции украшения) . Каналы с отслеживанием состояния применяются к данному объекту только один раз. Вы можете изменить определение канала (конечно, не в источнике A2) или сделать что-то, чтобы принудительно изменить данные.

Итак, первый способ решить эту проблему - создать и использовать новый канал без сохранения состояния:

@Pipe({name: 'myDate', pure: false})
export class MyDatePipe implements PipeTransform {
  transform(value: any, pattern: string = 'mediumDate'): string {
    return (new DatePipe()).transform(value, pattern);
  }
}

Я подготовил пример plnkr. Это просто и многоразово, поэтому я бы порекомендовал это решение для небольших данных.

Хотя это также можно решить с помощью ChangeDetector и его markForCheck() метод после каждого обновления даты - этот будет более эффективным. Или, как сказал Дмитрий, просто создавайте новый объект даты каждый раз, когда хотите изменить данные.

person Daniel Kucal    schedule 10.11.2016

Вам необходимо переназначить переменную даты с новой ссылкой на дату.

this.myDate = new Date(this.myDate.setMonth(this.myDate.getMonth() + 1));

Как указано в документации

этот канал помечен как чистый, поэтому он не будет повторно оцениваться при изменении входных данных. Вместо этого пользователи должны рассматривать дату как неизменяемый объект и изменять ссылку, когда каналу необходимо повторно запустить

person Michael    schedule 10.11.2016

Похоже, что каналы запускают обновления не после обновления связанного объекта, а после обновления ссылки для объекта.

Вы можете исправить это, переназначив this.myDate, как показано ниже:

this.myDate = new Date(this.myDate.setMonth(this.myDate.getMonth() + 1));

person Dmitry Rusakov    schedule 10.11.2016