实现动态时区选择器Angular 2/4/5

时间:2017-11-11 08:31:47

标签: angular timezone momentjs angular2-moment

我需要在Angular 4/5应用程序中构建一个TimeZone选择器。当用户更改时区时,我希望页面上所有显示的时间值立即更新。

我打算使用:

  • 使用angular2-momentangular-moment-timezone支持时区的时刻。
  • 格式化日期使用amLocal管道,然后是其他管道。
  • 当用户选择其他时区时,我打算拨打moment.tz.setDefault(_timezone)

从此时开始,上述值被格式化为新时区,而当前显示的时间值不会更改。角度变化检测机制不会更新显示的时间值,因为输入值没有改变。

由于性能开销,我不想创建“不纯”管道(考虑到时区变化不是常见的活动)。

作为后备,我可以创建一个以当前时区为参数的管道(或使用现有管道)。它确实有效,但我需要将当前时区值传递给每个组件和模板。

即使没有更改值,我也无法找到Angular变化检测的方法来相信存在变化。

欢迎任何建议。

2 个答案:

答案 0 :(得分:2)

管道不是组件(显而易见),除了pure标志外,它们没有自己的变更检测机制。因此,有两种方法可以达到预期的效果:

  1. 使用智能不纯的管道,它将跟踪以前的值和以前的格式化结果。 Angular的AsyncPipe(实际上是不纯的,如果有另一种方法可以做到这一点,那么我相信它会变得纯净)就是这样实现的:

    if (value !== this.value || this.timeZoneChanged) 
    {
        this.value = value;
        this.formattedValue = ... render value ...;
    }
    return this.formattedValue;
    

    您可以在github上浏览AsyncPipe源代码。

  2. 使用自定义组件呈现日期,即自定义ControlValueAccessor

答案 1 :(得分:1)

例如,当使用ngx-translate时,切换语言意味着获取新的翻译。正如你所看到的那样here他们使用了一个不纯的管道,正如你所说的暗示性能问题。

我想象的另一种方法是定义可用于整个应用的组件DateComponent。这样,您就不会拥有{{ value | formatDate }} html <custom-date [date]="new Date()"></custom-date>,而是拥有@Component({ selector: 'custom-date', template: '<span>{{ formatedDate }}</span>' }) export class DateComponent { @Input() date: string; timezone: string; formatedDate: string; constructor(private userService: UserService) {} ngOnInit(){ this.timezone = this.userService.getTimeZone(); this.updateValue(); this.userService.onTimezoneChange() .subscribe(timezone => { this.timezone = timezone; this.updateValue(); }); } updateValue() { // Do your formatting the way you want this.formatedDate = moment(this.date).tz(this.timezone).format(); } }

在您的自定义日期组件中将如下所示

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:id="@+id/accueil_toolbar_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="16dp"
        android:text="Accueil"
        android:textSize="20dp" />

    <View
        android:id="@+id/separator"
        android:layout_width="match_parent"
        android:layout_height="2dp"
        android:background="@android:color/darker_gray" />

    <ListView
        android:id="@+id/accueil_fragment_list"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"/>
</LinearLayout>