ember-polyfills / ember-angle-bracket-invocation-polyfill

MIT License
76 stars 33 forks source link

Ensure class and id attributes work properly. #4

Open rwjblue opened 6 years ago

rwjblue commented 6 years ago

Using the following should set id and class on the rendered element:

<FooBar class=“big” id=“awesome-123” />

The current system adds to attributeBindings, but since class and id are “special” we should add some tests to ensure they work properly.

willviles commented 6 years ago

@rwjblue, what's the recommended way of accessing these attributes in a tagless component?

Passing ...attributes works when blanket applying attrs to a div in the template, but I'd like to extend/modify before usage.

I noticed the values are exposed via this.__ANGLE_ATTRS__.{class|id}.inner.

rwjblue commented 6 years ago

Passing ...attributes works when blanket applying attrs to a div in the template, but I'd like to extend/modify before usage.

It should not be possible to access attribute values in the component JavaScript at all. If your component needs to do something with a value it should be passed as a named argument (e.g. as @class={{something}} instead of class=).

I noticed the values are exposed via this.__ANGLE_ATTRS__.{class|id}.inner.

This is a private implementation detail of this polyfill, when Ember 3.4+ is used this will not work...

willviles commented 6 years ago

@rwjblue, thanks for the explanation!

tschoartschi commented 5 years ago

I know it's not totally related to this issue but I stumbled across this issue when I searched for a way to access the ...attributes

It should not be possible to access attribute values in the component JavaScript at all. If your component needs to do something with a value it should be passed as a named argument (e.g. as @class={{something}} instead of class=).

I'm not 100% sure if this constraint is very beneficial. We have the following problem:

We have an input component which adds some html around the regular input. This html should be "greyed out" when the input is disabled. Therefore we use a CSS class. The hbs looks something like:

<div class="c-select{{if this.disabled " disabled"}}">
    <label for="objecttype">{{@label}}</label>
    <select id="objecttype" disabled={{this.disabled}} ...attributes>
        {{yield}}
    </select>
    {{#if @hint}}
        <div class="hint">{{@hint}}</div>
    {{else}}
        <div class="spacer">&nbsp;</div>
    {{/if}}
</div>

Now the "user" of this component needs to know exactly what attributes are JS specific and which are HTML only. Since disabled is also a HTML attribute this is not very intuitive for the "user" of the component. The invocation would look something like:

<CustomInput
    @hint="hint"  // okay, hint is no HTML attribute use @
    @label="label"  // okay, label is no HTML attribute use @
    @disabled=this.isSaving   // okay, disabled is a HTML attribute but we use it in JS as well so use @
    id="id"  // okay, id is a HTML attribute do not use @
    name="name"  // okay, name is a HTML attribute do not use @
    class="some-extra-css"  // okay, class is a HTML attribute do not use @
/>

This didn't seem so nice to us so we decided to try to workaround this problem. Then we thought we could use the did-update modifier but the did-update only fires when you sepecify which arguments should be "watched" and therefore we can not set HTML attributes internally.

Maybe I just think wrong or I overlook something but I'm not sure how to solve this and keep a nice api for the "component user"