Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I bind a value to a web component's attribute using Angular?

Let me preface this by saying that I've never really used Angular before. I'm trying to debug a problem one of the users of my web component library is facing.

I have a custom element, using lit-element, that has a boolean property. That boolean property has a custom attribute converter that makes it treat the string "false" as falsy (as opposed to native html element boolean attributes where the presence of the attribute makes it true). The converter looks like this:

{
  fromAttribute(val) {
    if (val === 'false') {
      return false;
    }
    if (val === '') {
      return true;
    }
    return Boolean(val);
  },
  toAttribute(val) {
    if (!val) {
      return null;
    }
    return '';
  }
}

As far as I can tell, Angular has 2 ways of binding a value to an html element in the template:

  1. By attribute, enabled="{{ enabled }}"
  2. By property, [enabled]="enabled"

For native elements like <img>, the attribute binding works as expected - I can see the attribute when I inspect the html.

For custom elements, attributes don't appear to be set at all - Angular seems to be setting a property no matter what. But, it is stringifying the value.

Here's a stackblitz that tries to demonstrate this: https://stackblitz.com/edit/angular-lit-element-1vz1nf?file=src%2Fapp%2Fapp.component.ts

I have a custom <hello-world> component that accepts a name, and enabled. If you inspect the html, name is not set as an attribute at all. enabled is set, but not to the value I'd expect.

There's also an <img> tag, where src is being set correctly.

Does angular special case custom elements and only ever set properties? Is this documented somewhere? To me it feels like a bug, and breaks some people's code who are using my custom elements in Angular.

like image 922
Brian Schlenker Avatar asked Mar 02 '23 20:03

Brian Schlenker


1 Answers

To bind to attributes, you need to use the [attr.*] binding, otherwise you are binding to properties of the element, or @Input() of the custom element/component. In your example this would look like:

<hello-world name="{{ name }}" [attr.enabled]="enabled"></hello-world> 

stack

You also have the @Attribute() decorator. I've added an example of it to the stack. I don't know how this would look like in a custom element. I do know that you can't do dynamic binding to it. The value needs to be fixed, and needs to be string

like image 152
Poul Kruijt Avatar answered Mar 05 '23 15:03

Poul Kruijt