【问题标题】:Angular 2 periodically refresh viewAngular 2 定期刷新视图
【发布时间】:2017-11-06 23:54:44
【问题描述】:

我正在使用 moment.js .fromNow() 显示项目列表及其相对创建日期,如下所示:

getRelativeDate(date: string): string {
  return moment(date, 'YYYY-MM-DD HH:mm:ss').fromNow();
}

<div class="created">{{getRelativeDate(item.created)}}</div>

这就是它的样子:

但是除非我以某种方式与项目交互,否则它在初始加载后保持不变,这是有道理的,因为数据没有改变,当前时间是。

如何强制刷新这些值?每一分钟就足够了。

【问题讨论】:

  • 这将取决于您的 item 数据是否异步。如果数据不是异步的,你可以在ngOnInit()中创建一个setInterval(),如果数据是异步的,你可以在获取数据后创建setInterval()

标签: javascript angular model-view-controller momentjs


【解决方案1】:

对没有人提到为此创建管道感到惊讶吗?

import { Pipe, PipeTransform } from '@angular/core';

import moment from 'moment';

@Pipe({
  name: 'dateTimeFormat',
  pure: false,
})
export class DateTimeFormatPipe implements PipeTransform {
  transform(date: string, format: string = 'YYYY-MM-DD HH:mm:ss'): string {
    return moment(date, format).fromNow();
  }
}

这通过将逻辑卸载到管道中来保持组件清洁。

<ul>
  <li *ngFor="let date of dates">
    {{ date | dateTimeFormat:'YYYY-MM-DD HH:mm:ss'}}
  </li>
</ul>

很酷的是格式是可选的,可以在整个应用程序中重复使用。

然后要定期更新组件刷新调用setInterval。 您还需要调用ChangeDetectorRef 并根据您的ChangeDetectionStrategy 调用detectChanges。更好的是,detach 组件完全。

现场示例 https://stackblitz.com/edit/angular-cli-moment-pipe

有用的 Moment Pipes 集 https://github.com/urish/angular2-moment/

【讨论】:

  • 这是正确的答案。不敢相信我之前没想到! :D
  • changeDetection: ChangeDetectionStrategy.OnPush 是否意味着它不会在数据更改时自动更新视图?只有当我运行detectChanges()?
  • 它只会在检测到@Input() 绑定更改时更新视图。由于我的示例组件中没有@Input() 绑定,因此组件更新的唯一时间是我手动调用detectChanges 时。更好的方法是完全分离组件。这确保了整个应用程序不会在每次setInterval 触发时检查更改。我已经按答案更新了。
  • 您是要分离整个列表(在本例中为ul)还是每个项目(li)?因为前者很难做到,而后者如果我的列表很长,会导致数百个定时器运行,不是吗?
  • 否,分离显示列表的组件。每次发生 setInterval 时,Angular 都会对整个应用程序运行更改检测。通过分离组件(参见我的 stackblitz),它不会强制整个应用程序刷新
【解决方案2】:

使用setInterval

我们需要ChangeDetectorRef 来执行此操作。

import {OnInit, OnDestroy, ChangeDetectorRef} from '@angular/core';

export class Listcomponent implements OnInit, OnDestroy {

   intervalHolder: any;

   constructor(private _changeDetectorRef: ChangeDetectorRef) {
   }

   ngOnInit(): void {
     this.intervalHolder = setInterval(() => {
       // Let's refresh the list.
       this._changeDetectorRef.markForCheck();
     }, 1000 * 60); // 1 minute
   }

   ngOnDestroy(): void {
      clearInterval(this.intervalHolder);
   }
}

【讨论】:

    【解决方案3】:

    如果您的数据不是异步的,您可以在ngOnInit() 中创建一个setInterval(),然后将其清除ngOnDestroy()。假设您创建的日期存储在名为 items 的数组中,位于键 created 下:

    component.ts

    myFromNowInterval: any;
    myFromNow = Array(this.items.length).fill('');
    
    ngOnInit() {
      this.myFromNowInterval = setInterval( () => {
        this.items.forEach( (item, index) => this.myFromNow[index] = this.getRelativeDate(item) )
      }, 60000);
    }
    
    ngOnDestroy() {
      clearInterval(this.myFromNowInterval);
    }
    

    component.html

    <div *ngFor="item of items; let i = index;">
      <div class="created">{{ myFromNow[i] }}</div>
    </div>
    

    这将每分钟更新一次myFromNow 数组,并将新数组的索引与 DOM 对齐。

    【讨论】:

      【解决方案4】:

      我认为只需在组件上放置一个可观察的间隔就足以触发更改检测。

      triggerCD$;
      
      ngOnInit() {
        this.triggerCD$ = Observable.interval(60000)
      }
      

      用这个测试

      <span>{{ now() }}</span>
      
      now() {
        const now: any = new Date();
        return (now - this.start)
      }
      

      没有触发器,显示不会改变。
      使用触发器,now() 更新模板(尽管没有直接链接到触发器)。

      【讨论】:

        猜你喜欢
        • 2019-05-04
        • 2023-03-28
        • 2018-04-11
        • 2021-05-09
        • 2019-08-30
        • 1970-01-01
        • 1970-01-01
        • 2014-08-11
        • 2012-10-12
        相关资源
        最近更新 更多