23

在角度 4 变化检测系统中显示当前时间的正确(规范)方法是什么?

问题如下:根据定义,当前时间每时每刻都在不断变化。但 Angular 4 变化检测系统无法检测到它。因此,在我看来,有必要显式调用ChangeDetectorRef::detectChanges. 但是,在调用这个方法的过程中,当前时间自然会改变它的值。这导致ExpressionChangedAfterItHasBeenCheckedError. 在以下示例中(请参阅 live),在加载页面后几秒钟内会出现此错误:

import { Component, ChangeDetectorRef } from '@angular/core';
@Component({
    selector: 'my-app',
    template: `{{ now }}<br />{{ now }}<br />{{ now }}<br />{{ now }}<br />{{ now }}<br />{{ now }}<br />
        {{ now }}<br />{{ now }}<br />{{ now }}<br />{{ now }}<br />{{ now }}<br />{{ now }}<br />
        {{ now }}<br />{{ now }}<br />{{ now }}<br />{{ now }}<br />{{ now }}<br />{{ now }}<br />
        {{ now }}<br />{{ now }}<br />{{ now }}<br />{{ now }}<br />{{ now }}<br />{{ now }}<br />
        {{ now }}<br />{{ now }}<br />{{ now }}<br />{{ now }}<br />{{ now }}<br />{{ now }}<br />
        {{ now }}<br />{{ now }}<br />{{ now }}<br />{{ now }}<br />{{ now }}<br />{{ now }}<br />
        {{ now }}<br />{{ now }}<br />{{ now }}<br />{{ now }}<br />{{ now }}<br />{{ now }}<br />
        {{ now }}<br />{{ now }}<br />{{ now }}<br />{{ now }}<br />{{ now }}<br />{{ now }}`
})
export class AppComponent {
    get now() : string { return Date(); }
    constructor(cd: ChangeDetectorRef) {
        setInterval(function() { cd.detectChanges(); }, 1);
    }
}
4

7 回答 7

45

首先,您不需要ChangeDetectorRef.detectChanges()在间隔内调用,因为 Angular 正在使用哪个猴子用自己Zone.js的方法修补浏览器方法。setInteral因此 angular 很清楚间隔期间发生的变化。

您应该像这样在间隔内设置时间:

import { Component } from '@angular/core';
@Component({
    selector: 'my-app',
    template: `{{ now }}`
})
export class AppComponent {
    public now: Date = new Date();

    constructor() {
        setInterval(() => {
          this.now = new Date();
        }, 1);
    }
}

但是您不应该以如此高的速率更新时间,因为这会导致性能不佳,因为每次日期更新角度都会在组件树上执行更改检测。

如果你想以非常高的速度更新 DOM,你应该使用runOutsideAngularfromNgZone并使用Renderer2.

例如:

@Component({
  selector: 'my-counter',
  template: '<span #counter></span>'
})
class CounterComponent implements OnChange {
  public count: number = 0;

  @ViewChild('counter')
  public myCounter: ElementRef;

  constructor(private zone: NgZone, private renderer: Renderer2) {
    this.zone.runOutsideAngular(() => {
      setInterval(() => {
        this.renderer.setProperty(this.myCounter.nativeElement, 'textContent', ++this.count);
      }, 1);
    });
  }
}
于 2017-10-04T10:18:10.947 回答
14

根据DatePipe Link上的 Angular 文档,Date.now()可以使用。

import { Component } from '@angular/core';
@Component({
    selector: 'my-app',
    template: `{{ now | date:'HH:mm:ss'}}`
})
export class AppComponent {
    now:number;

    constructor() {
        setInterval(() => {
          this.now = Date.now();
        }, 1);
    }
}
于 2018-08-20T19:59:09.380 回答
6

实际上,这个简单的任务不需要任何库。如果您正在使用 angular 6+ 进行 angular 项目,则从 common 包中导入 formatDate 并传递其他数据。这是一个示例:

import { Component } from '@angular/core';
import {formatDate } from '@angular/common';
@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  today= new Date();
  todaysDataTime = '';

  constructor() {
    this.todaysDataTime = formatDate(this.today, 'dd-MM-yyyy hh:mm:ss a', 'en-US', '+0530');
  }
}

这是一个 stackblitz 链接,您可以在此处编辑:https ://stackblitz.com/edit/angular-h63y8e

于 2019-07-27T22:01:11.500 回答
5
today: number = Date.now();

constructor() {
    setInterval(() => {this.today = Date.now()}, 1);
}

如果要在 html 页面上对其进行格式化,请像这样使用它:

<p>{{today | date:'fullDate'}} {{today | date:'h:mm:ss a'}}</p>

我正在添加一个点,我正在寻找并且可能因为这个答案而更接近我的解决方案,所以对于另一个正在寻求类似事情的人,我也在添加这个:)

如果你想得到 [Year: Month :date :hours: minutes with am/pm ] 格式的所有数字(例如:12 而不是字符串“December”),只需使用以下

<p>{{today | date:'y:M:d:h:mm a'}}</p>
于 2019-07-18T05:18:24.277 回答
3
CurrentTime: any;
  constructor() {
    setInterval(() => {
      this.CurrentTime = new Date().getHours() + ':' + new Date().getMinutes() + ':'+  new Date().getSeconds()}, 1);
  }
于 2019-02-18T22:07:15.097 回答
0

如果我们使用反应形式,角度为 2+

<input formControlName="scheduleTime" type="time"  class="form-control ">


this.orderForm.controls.scheduleTime.setValue(new Date().toString().split(' ')[4]);

使用上面的代码,我们将在时间输入中显示当前时间

于 2021-07-24T04:26:07.593 回答
-2

使用箭头功能。

constructor(cd: ChangeDetectorRef){
    setInterval(() => { cd.detectChanges();  }, 1);
  }
于 2017-10-04T10:07:35.577 回答