5

Does anyone know why you can use [id] and you must use [attr.contenteditable] as property binding in Angular?

I have researched for some time and I can't find an answer.

Why some html native attributes can be modified just with its name while others need to be modified through the attr property?

  • Check this:https://stackoverflow.com/questions/39112904/property-binding-vs-attribute-interpolation – Chellappan வ Feb 24 '20 at 11:50
  • Some specific attrs are defined in Angular definitions. But all cannot be defined, so for that reason there is 'attr' option. By the way, also 'attr.id' will work! – Andris Feb 24 '20 at 11:53

3 Answers3

5

(This answer assumes you're binding to a HTMLElement rather than an in-app model object. Given the [attr.{name}]-syntax is only supported for DOM HTMLElement objects this assumption should stand)

When working with the DOM, the DOM interfaces for certain elements define first-class/native properties (as in JavaScript properties) for certain HTML attributes.

For example, the HTMLElement DOM interface defines a first-class property id, which is why you can directly use it in a binding expression: [id]. Similarly the HTMLAnchorElement exposes the href property.

(I note that contenteditable is a a defined DOM interface property in WHATWG HTML LS, but not the W3C's DOM specs, interesting...)

However, arbitrary (ultra-modern, user-defined, and obsolete) HTML attributes are not exposed through DOM interfaces and so can can only be accessed via the attributes collection in the DOM. Angular requires you to use [attr.{name}] for non-DOM-property attributes so that it knows it has to use the attributes collection instead of assuming it can bind directly to a DOM property.

To answer your question more directly:

when use [name] vs [attr.name]?

Follow this flow-chart:

  • Is the value I'm after exposed as a DOM interface property?
    • Yes:
      • Use [propertyName]
    • No:
      • Is the value I'm after a HTML attribute without a corresponding DOM interface property?
        • Yes: Use [attr.{attributeName}]
        • No: Quit your job and let someone else deal with the emotional and mental stresses of the fast-moving JavaScript developer ecosystem.
Dai
  • 141,631
  • 28
  • 261
  • 374
  • contenteditable is exposed as `[contentEditable]`. I didn't realise this until I tried it just now, and always assumed we had to use `[attr.contenteditable]`. – Kurt Hamilton Feb 24 '20 at 12:00
  • 1
    @KurtHamilton Dang - you're right. `contenteditable` **is** a member of `HTMLElement` now: https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/contentEditable - derp! I'll update my answer. – Dai Feb 24 '20 at 12:01
  • 1
    @Dai I followed your flowchart and quit my job. Thanks! But seriously, I tend to prefer using `[attr.xxx]`, even if the DOM interface equivalent is available. I guess I'm just old fashioned. – Kurt Hamilton Feb 25 '20 at 08:10
3

From the docs

Though the target name is usually the name of a property, there is an automatic attribute-to-property mapping in Angular for several common attributes. These include class/className, innerHtml/innerHTML, and tabindex/tabIndex.

So not all attributes are mapped within Angular.

Using the attr. prefix will literally emit the suffix as a string attribute.

Take this example:

<div [attr.data-my-attr]="value"></div>

Will produce the following HTML, assuming that the component property value has a value of 5:

<div data-my-attr="5">
</div>

Why you must use [attr.contenteditable]="editable"?

This isn't true. This is one way of emitting the contenteditable="true" attribute. Another is to use the Angular attribute [contentEditable]="editable", assuming some component property editable exists.

<div [contentEditable]="editable"></div>

DEMO: https://stackblitz.com/edit/angular-ujd5cf

Kurt Hamilton
  • 12,490
  • 1
  • 24
  • 40
1

The reason is because most common HTML attributes have special @Input properties in angular itself. E.g. id class etc, but there are way too many attributes to have this for each of them, so those more specific require you to use attr. syntax. The same thing happens with shorthand binding e.g. [style.width.px], you cannot do this with every single property. Event bindings have similar behavior. E.g. you can say (keyup.enter) but not (keyup.j). Angular tries to make your life easier when it can with most common things, but it also provides option to do other things as well. This also means that you can do e.g. [attr.id]=

Blind Despair
  • 3,190
  • 2
  • 20
  • 31