When to use square brackets [ ] in directives @Inputs and when not?
Asked Answered
P

6

88

I'm confused a little.

See this simple directive:

 @Directive({
      selector: '[myDirective]'
    })
    export class MyDirective {

      private text: string;
      private enabled: boolean;

      @Input() myDirective:string;

      @Input('myText')
      set myText(val: string) {
        this.text = val;
      }

      @Input('myEnabled')
      set myEnabled(val: boolean) {
        this.enabled = val;
      }

      ngOnInit() {

        console.log("myDirective string: " + this.myDirective);
        console.log("myText string: " + this.text); 
        console.log("myEnabled boolean: " + this.enabled);
    }
}

if my html will look like this:

<div [myDirective]="myDefaultText" [myEnabled]="true"  [myText]="abc"></div>

The output will be:

myDirective string: myDefaultText real value  // good
myEnabled boolean: true                       // good
myText string: undefined                      // Why?

If I REMOVE the [] from myText:

<div [myDirective]="myDefaultText" [myEnabled]="true"  myText="abc"></div>

The output will be:

myDirective string: myDefaultText real value  // good
myEnabled boolean: true                       // good
myText string: abc                            // GOOD

I can also remove the [] from myEnabled and it will work too. So here is my confusion - when I need to use square brackets [] and when not, while I want the user who is going to use myDirective will never need to wonder if or if not, I think the square brackets [] should always be there. Aren't they?

Pitching answered 26/4, 2017 at 11:53 Comment(0)
R
75

When you use [] to bind to an @Input(), it's basically a template expression.

The same way displaying {{abc}} wouldn't display anything (unless you actually had a variable called abc).

If you have a string @Input(), and you want to bind it to a constant string, you could bind it like this: [myText]=" 'some text' ", or in short, like a normal HTML attribute: myText="some text".

The reason [myEnabled]="true" worked is because true is a valid template expression which of course evaluates to the boolean true.

Recidivism answered 26/4, 2017 at 12:0 Comment(3)
I didn't even think that's what's actually happening, are you sure? The asker mentioned that [myDirective]="myDefaultText" gave the input "myDefaultText real value", I though he meant the actual value of myDefaultText, which means it's still treated as an expression.Recidivism
This is covered in the current Angular 4 documentation on this page.Toed
Also be aware that if the @Input is defined with a default string value, and you use myvar="'new string'", it will not be overwritten... The keyword is constant as mentioned in this answer. That was a gotcha! for me.Carboxylate
A
52

If you write <img [src]="heroImageUrl"> it means that the right-hand side heroImageUrl is a template expression.

The simple difference between [myText]="abc" and myText="abc" is that in former you are asking angular to set the target PROPERTY myText using the template expression abc, while in the latter you setting the target property called myText using the string 'abc'.

Let's understand a little more about HTML.

In HTML you can define an element like this.

<input type="text" value="Bob">

input is an element whose attributes are type and value. When your browser parses this, it will create a DOM entry (an object) for this element. The DOM entry will have some properties like align, baseURI, childNodes, children etc. So, that's the difference between HTML attributes and DOM properties See reference. Sometimes the attribute and property have same names which causes confusion. For above input tag, it has the attribute value = Bob and also has a property value that will have the value of whatever you type in the text box. In summary, attribute is what you define about the tag, and property is what gets generated in the DOM tree.

In the world of Angular, the only role of attributes is to initialize element and possibly directive state. When you write a data binding, you're dealing exclusively with properties and events of the target object. HTML attributes effectively disappear.

So to summarize, in <div [myDirective]="myDefaultText" [myEnabled]="true" [myText]="abc"></div> you essentially are saying that:

  1. apply the directive myDirective to my div element.
  2. bind the variable myEnabled to the expression on the right. The expression says true, so the value of myEnabled is true.
  3. bind the variable myText to the expression on the right. The expression says abc. Is there any abc defined? No, so the expression evaluated to undefined.
Atypical answered 15/1, 2019 at 19:22 Comment(1)
This is the only answer that actually explains the reason rather than just showing some side effects. Kudos.Tipton
W
17

The brackets tell Angular to evaluate the template expression. If you omit the brackets, Angular treats the string as a constant and initializes the target property with that string. It does not evaluate the string!

Don't make the following mistake:

    <!-- ERROR: HeroDetailComponent.hero expects a
         Hero object, not the string "currentHero" -->
    <hero-detail hero="currentHero"></hero-detail>

check: https://angular.io/docs/ts/latest/guide/template-syntax.html#!#property-binding

Whim answered 26/4, 2017 at 12:3 Comment(1)
Accurate and best answerValvule
O
12

binding [] is for objects, without it the value is string. Be careful about types.

In the code

<div [myDirective]="myDefaultText" [myEnabled]="true"  [myText]="abc"></div>

you have tried to bind the object, but the object is not available, thus it's value is undefined. On the other hand if you remove binding then the object is gone, you have only a string value assigned to the property.

Ornithorhynchus answered 26/4, 2017 at 12:11 Comment(3)
Make sure not to do myEnabled="false" because that will be evaluated as a string and since "false" is actually a truthy value it won't behave as you expected.Fukuoka
Where did you see that?Ornithorhynchus
Not sure why you posted that link, but just realized I never replied to your previous comment. My guess is I must've spent an hour trying to debug something similar myself when I'd forgotten the brackets - and wanted to stress the point to others reading your answer (even though you already mentioned strings). :-)Fukuoka
C
6

From Angular guide on property binding:

The brackets, [], cause Angular to evaluate the right-hand side of the assignment as a dynamic expression. Without the brackets, Angular treats the right-hand side as a string literal and sets the property to that static value.

Cannikin answered 28/4, 2021 at 19:42 Comment(0)
B
5

This is the latest update for Angular 13.

Let's take an example...

Suppose we have an input variable named carImage, which will contain the dynamic URL value passed from the parent.

@Input() carImage = '';

Scenario 1 - With the square brackets

<img [src]="carImage"></img>

In this case, whatever the value the carImage variable holds will be assigned to the src attribute of img. This is the property binding, where we can set the values for attributes dynamically.

Scenario 2 - Without the square brackets

<img src="carImage"></img>

In this case, the string carImage will be directly assigned to the src attribute, hence Angular will not be able to display the image since it is an invalid URL.

To make it work, you have to assign a valid URL, as shown below.

<img src="http://demo/carImage.jpg"></img>
Billups answered 7/1, 2022 at 6:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.