Deepak Kumar
Deepak Kumar

Reputation: 972

Implementing a dynamic Time Zone selector Angular 2/4/5

I need to build a TimeZone selector in my Angular 4/5 Application. When a user changes the timezone, I expect all displayed time values on the page to update immediately.

I was planning to use:

With the above values from this point on gets formatted as new time zone, while currently displayed time values do not change. Angular change detection mechanism does not update displayed time values, as the input values have not changed.

I do not want to create an 'impure' pipe because of performance overheads (considering timezone change is not a frequent activity).

As fallback I can create a pipe (or use an existing one) that takes the current time zone as parameter. It actually works but I will need to pass around the current time zone value to each component and template.

I have not been able to find a way for Angular change detection to believe there is a change even when there was no change of values.

Any suggestions will be welcome.

Upvotes: 1

Views: 3509

Answers (2)

Pierre Clocher
Pierre Clocher

Reputation: 1117

When using for example ngx-translate for example, switching the language imply fetching new translation. As you can see here they use an impure Pipe which as you said imply performance issues.

The other way I imagine is to define a component DateComponent available for your whole app. That way, instead of having in your html {{ value | formatDate }} you'll have <custom-date [date]="new Date()"></custom-date>.

In your custom date component will look like this

@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();
  }
}

Upvotes: 1

kemsky
kemsky

Reputation: 15288

Pipes are not components (obvious), they do not have their own change detection mechanics except pure flag. So there two ways to achieve desired result:

  1. Use smart impure pipe which will track previous value and previous formatted result. Angular's AsyncPipe (which is impure actually, if there was another way to do that then I believe it would be made pure) is implemented this way:

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

    You can browse AsyncPipe source code on github.

  2. Use custom component to render dates i.e. custom ControlValueAccessor.

Upvotes: 2

Related Questions