Dealing with "stubborn" web components in Angular

Web components are great, and one of the things making them great is that they are sealed packages the innards of which you do not need to know. Unfortunately, that also means you don't have many options when that component is misbehaving.

The web component I just had to deal with was a date input field augmented with flatpickr. The problem was that the component would not update its flatpickr when the attribute responsible for its configuration was changed after the first rendering, nor did the web component provide a method to force an update.

In the end, I came up with a rather wretched but functional hack-around, which looks like this:

  selector: 'my-wrapper.component',
  templateUrl: './my-wrapper.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush
export class MyWrapperComponent implements OnChanges {

  @Input() componentOptions: any;

  componentOptions$ = new BehaviorSubject<any>({});

  flipFlop$ = new BehaviorSubject(0);

  ngOnChanges(changes: SimpleChanges) {
    if (changes.componentOptions) {
      this.flipFlop$.next((this.flipFlop$.value + 1) % 2);

and, in the template:

<ng-container *ngFor="let i of [0, 1]">
  <ng-container *ngIf="i === (flipFlop$ | async)">
      [problematicOptions]="componentOptions$ | async"

(I've used two nested ng-container pseudo-elements to better illustrate, but of course the *ngIf could be attached directly to the web component.)

Well, I said it would be ugly. But this works: because of the flipFlop$ value, Angular has no choice but to re-render the web-component, which will of course have to initialize any sub-components it might be using from scratch.

Caveat: just as this trick does away with unwanted state, it could also destroy desirable state, such as - just as an example - a file dialog no longer remembering the last folder you navigated to.

Hope this may be of help to someone - cheers!

No Comments Yet