45

I have read an article about difference between property and attribute bindings. From what I understood, most of the time, Angular2 prefers property bindings, because after each change in data, the DOM would be updated. (If I am mistaken, please correct me).

I have a custom component and use it from the parent component. In it, I have an @Input named truevalue. when I initiate truevalue from the parent via property binding, sometimes, it does not change. I used following code:

<my-checkbox [(ngModel)]="chkItems" [disabled]="!editMode" [trueValue]="Y"></my-checkbox>

If I send true or "1" into trueValue it works, but If I send "Y" or "YES", it does not work. So I am forced to use attribute binding. I don't know what is the problem.

I have changed it, into the following:

<my-checkbox [(ngModel)]="chkItems" [disabled]="!editMode" trueValue="Y"></my-checkbox>

Thanks in advance

developer033
  • 24,267
  • 8
  • 82
  • 108
Maryam Gharibi
  • 531
  • 1
  • 5
  • 13

7 Answers7

57

Property binding like

[trueValue]="..."

evaluates the expression "..." and assigns the value

"true" evaluates to the value true "Y" is unknown. There is no internal Y value in TypeScript and no property in the component class instance, which is the scope of template binding. In this case you would want

[trueValue]="'Y'"

Note the additional quotes to make Y a string.

Plain attributes are also assigned to inputs

trueValue="Y"

is plain HTML without any Angular2 binding and attribute values are always strings. Therefore this would assign the string Y.

Another way is string interpolation

trueValue="{{true}}"

would assign the value "true" (as string) because the expression withing {{...}} would be evaluated and then converted to a string before passed to the input. This can't be used to bind other values than strings.

To explicitly bind to an attribute instead of a property you can use (besides trueValue="Y" which creates an attribute but doesn't do any evaluation)

[attr.trueValue]="'Y'"

or

attr.trueValue="{{'Y'}}"

Attribute binding is helpful if you want to use the trueValue attribute to address the element with CSS selectors.

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • But which one of the last two examples provided by you should be preferred? – Marek Jan 27 '21 at 12:55
  • 1
    There is no general suggestion as far as I am aware of. Use what you prefer. I personally prefer `[]` because I hardly ever use `{{}}` on attributes, only in element content, so I think it helps with distinguishing attributes from contents visually. – Günter Zöchbauer Jan 27 '21 at 13:45
  • Is the Angular bracket-less syntax (`attr.trueValue="{{'Y'}}"`) documented somewhere? – Aardvark Apr 06 '23 at 14:48
  • @Aardvark definitively. `{{}}` and `[]` should not be used together. `[]` is for property binding that allows object values to pass to properties. `{{}}` alsways stringifies the value and therefore is best used only for attributes always take string values. Angular inputs are treated like properties https://stackoverflow.com/questions/6003819/what-is-the-difference-between-properties-and-attributes-in-html – Günter Zöchbauer Apr 06 '23 at 14:57
  • @GünterZöchbauer Sorry, I was asking specifically about the use the "attr." prefix *without* square brackets. Like why is there this `attr.data-test={{...}}` vs just doing this: `data-test={{...}}`. Also, why does attr.data-test="literal-value" not work? – Aardvark Apr 13 '23 at 18:05
  • @Aardvark sorry, I missed the `attr.` prefix and that the question was about that. The brackets allow objects to be assigned, but they are stringyfied: "Then, you set the attribute value with an expression that resolves to a string." Without the brackets the assigned value is used as literal string value or as string with interpolation when `{{}}` is used. This isn't explicitly mentioned. I think that derives from the canonical forms of bindings, but I can't find that in the docs anymore. – Günter Zöchbauer Apr 14 '23 at 01:27
35

I came to understand from the following sentences

First I will explain a little bit about html attribute and dom property

  1. Attributes are defined by html whereas properties are defined by DOM
  2. Attributes initialise DOM properties. Once initialisation complete attribute job is done
  3. Properties value can change whereas attribute value cannot change

For example

 <input id="idInput" type="text" value="xyz" />

In console of a browser if we type

idInput.getAttribute('value') //attribute value gives xyz

idInput.value  // property value also gives xyz

If we change the input text in textbox to tyz:

idInput.getAttribute('value') // attribute value gives xyz

idInput.value  // property value also gives tyz

Now different types of binding in angular

String Interpolation {{name}}

  1. Interpolation is a special syntax that Angular convert into a property binding
  2. To concatenate strings we must use interpolation instead of property binding
  3. To set an element property to a nonstring data value, you must property binding

Property Binding [disabled]="name"
Here [disabled] is a property of DOM. Not the attribute disabled found in html.

Attribute Binding attr.colspan ="{{colspanval}}"
When property corresponding to the attribute doesn't exist for example colspan doesn't have corresponding dom property so attribute binding is required.
Error is thrown in console if we try to use colspan = "{{cospanval}}" - property binding

Vega
  • 27,856
  • 27
  • 95
  • 103
Nayas Subramanian
  • 2,269
  • 21
  • 28
15

When rendering data values as strings, there is no technical reason to prefer one form to the other.

If we want data values as boolean or other than string then we should go for property binding

ganesh kalje
  • 3,014
  • 2
  • 16
  • 12
9

A couple of others have mentioned this, but I think a good example is important to highlight the difference. Suppose you have some radio buttons that are bound like this:

<div *ngFor="let item of results">
  <input type="radio" value="{{item.id}}" name="{{item.id}}" [(ngModel)]="selectedItemId">
</div>

This would appear to work correctly, but if item.id is a numeric value rather than a string, selectedItemId would get set to a string value instead of an integer. This could cause defects in unexpected places. For example, using item.id == selectedItemId might return true when item.id === selectedItemId would always be false.

So I'd suggest that it's probably a good practice to always use property binding on the value property, because it's specifically used to store and bind to values rather than just changing the HTML.

<div *ngFor="let item of results">
  <input type="radio" [value]="item.id" name="{{item.id}}" [(ngModel)]="selectedItemId">
</div>

Same goes for boolean attributes. Note that in some cases like checked and disabled, Angular appears to treat interpolated values as booleans, but in others like hidden, it doesn't. See this stackblitz for an example.

StriplingWarrior
  • 151,543
  • 27
  • 246
  • 315
3

Property binding([]) and interpolation({{}}) , both are similar and both supports one way data binding(supply data from component to html template).There is a minor difference between them. We must use property binding for non-string data.such as

<div [disabled]='isdissabled'>Text</div>

 here is property that is defined inside component.

 isdissabled : boolean=true;(after that change it to false in both scenario it would work as expected)
<div disabled='{{isdissabled}}'>Text</div>

but this scenario would not work as expected(both scenario it would be dissabled).
Sheo Dayal Singh
  • 1,591
  • 19
  • 11
  • 4
    I don't think divs are allowed to be disabled. Can you update this with an example that reproduces the problem you're describing? – StriplingWarrior Feb 20 '19 at 21:15
2

Assuming my-checkbox is your custom component selector and you are using this in your parent component. As you have trueValue as @Input property on your custom component, in order to use it in parent component Y must evaluate to some value which it does in case of 1 (equivalent to true).

For property-binding to work, it must evaluate to a value. "YES" or "Y" are just string value which will not be evaluated unless you do something like :

export class ParentComponent` {
       Y = "YES"; // <--or "Y"
    }

and then display trueValue using interpolation in your custom component like {{trueValue}}

another thing to note is when you use {{}} i.e interpolation it always convert the value to .toString() before binding.

candidJ
  • 4,289
  • 1
  • 22
  • 32
2

Technically there are 3 ways to bind properties.

  1. String Interpolation - {{ expression }} - render the bound value from component's template and it converts this expression into a string.

  2. Property Binding - [target]="expression" - does the same thing by rendering value from component to template, but if you want to bind the expression that is other than string (for example - boolean), then property Binding is the best option.

  3. bind-target="expression" - This is not a regular way of using.

Its always your decision to use whichever option that fits your use case.

Alexander Abakumov
  • 13,617
  • 16
  • 88
  • 129
Sidd Thota
  • 2,040
  • 1
  • 20
  • 24