bb197
bb197

Reputation: 81

How to prevent web component from loading until template is filled in Angular

I'm using a web component in my angular app. I am using angular attribute bindings to dynamically fill my web component: https://angular.io/guide/attribute-binding

When I hardcode the values for my web component attributes, it works fine. However, when I dynamically bind the attributes, I run into issues.

What seems to be happening is the template loads, then the authVariable is set to the auth-token attribute once the component loads. The web component I am using throws an error when the template loads before the component loads. When the template is then filled with the authVariable, the web component doesn't recover from the error state.

The component I am using does have a default value for authVariable (I'm not doing an async call to get a value for authVariable).

My question is: What is the easiest way to have angular only load a filled version of the template?

This works fine

<web-component
  auth-token="<AUTH_TOKEN>"
>
</web-component>

This doesn't work

<web-component
[attr.auth-token]="authVariable"
>
</web-component>

Upvotes: 1

Views: 472

Answers (1)

kamoroso94
kamoroso94

Reputation: 1735

This is probably a bug with the web component itself. It should be able to detect changes to attributes with the attributeChangedCallback method. However, if you need to work around this issue, you would need to use outerHTML to insert the markup yourself to be evaluated all at once instead of when Angular feels like setting the attributes. Because you'll need to use bypassSecurityTrustHtml to get Angular to parse the non-trivial markup, you need to be confident that the template string you pass in has no security flaws (like interpolating user input), otherwise you'd be opening yourself up to XSS attacks.

// my.component.ts
import {DomSanitizer, SafeHtml} from '@angular/platform-browser';

@Component({…})
class MyComponent {
  private readonly authVariable = '…';
  protected readonly webComponent: SafeHtml;

  constructor(private readonly sanitized: DomSanitizer) {
    this.webComponent = this.sanitized.bypassSecurityTrustHtml(`
      <web-component auth-token="${this.authVariable}">
      </web-component>
    `);
  }
}
<!-- my.component.html -->
<template [outerHTML]="webComponent"></template>

Upvotes: 1

Related Questions