139

When writing Angular 2.0 components, how does one set default values for properties?

For example - I want to set foo to 'bar' by default, but the binding might immediately resolve to 'baz'. How does this play out in the lifecycle hooks?

@Component({  
    selector: 'foo-component'
})
export class FooComponent {
    @Input()
    foo: string = 'bar';

    @Input()
    zalgo: string;

    ngOnChanges(changes){
          console.log(this.foo);
          console.log(changes.foo ? changes.foo.previousValue : undefined);
          console.log(changes.foo ? changes.foo.currentValue : undefined);
    }
}

Given the following templates, this is what I expect the values would be. Am I wrong?

<foo-component [foo] = 'baz'></foo-component>

Logged to console:

'baz'
'bar'
'baz'
<foo-component [zalgo] = 'released'></foo-component>

Logged to console:

'bar'
undefined
undefined
MathMax
  • 571
  • 7
  • 22
Bryan Rayner
  • 4,172
  • 4
  • 26
  • 38
  • What happens when you try it? – JB Nizet Mar 17 '16 at 21:28
  • 1
    @BryanRayner the way currently console's are getting printed are correct..what is the problem which you facing? – Pankaj Parkar Mar 17 '16 at 21:58
  • 8
    I am not currently facing a problem, just seeking clarification on the intended behavior. When I didn't find the answer to my curiosity, I decided I would ask the question in case others had the same desire for clarity. – Bryan Rayner Mar 17 '16 at 22:41
  • In your example you are missing the parenthesis on the @Input() – kitimenpolku Oct 19 '16 at 06:16
  • For those who are still searching for answer there is "Input setter coercion" in angular official documentation where you are working with getters and setters of an input. https://angular.io/guide/template-typecheck#input-setter-coercion – Zvonko Sep 17 '21 at 07:57

2 Answers2

185

That is interesting subject. You can play around with two lifecycle hooks to figure out how it works: ngOnChanges and ngOnInit.

Basically when you set default value to Input that's mean it will be used only in case there will be no value coming on that component. And the interesting part it will be changed before component will be initialized.

Let's say we have such components with two lifecycle hooks and one property coming from input.

@Component({
  selector: 'cmp',
})
export class Login implements OnChanges, OnInit {
  @Input() property: string = 'default';

  ngOnChanges(changes) {
    console.log('Changed', changes.property.currentValue, changes.property.previousValue);
  }

  ngOnInit() {
    console.log('Init', this.property);
  }

}

Situation 1

Component included in html without defined property value

As result we will see in console: Init default

That's mean onChange was not triggered. Init was triggered and property value is default as expected.

Situation 2

Component included in html with setted property <cmp [property]="'new value'"></cmp>

As result we will see in console:

Changed new value Object {}

Init new value

And this one is interesting. Firstly was triggered onChange hook, which setted property to new value, and previous value was empty object! And only after that onInit hook was triggered with new value of property.

Kanso Code
  • 7,479
  • 5
  • 34
  • 49
  • 12
    Is there any links to the official docs for this behavior? Would be good to understand the logic and reasoning behind this, also be able to track what the behavior is per version. – Bryan Rayner Dec 12 '16 at 17:42
  • I have not seen such info, all above is my own investigation. I think you can find more answers if you will read compiled js files – Kanso Code Dec 12 '16 at 17:47
  • 1
    I was looking for documentation on the `@Input` having default values. @slicepan has a link to the docs for the component lifecycle, but I did not see a default value used in the documentation. – nycynik Mar 12 '18 at 23:41
  • @nycynik simply use this for default values: `@Input() someProperty = 'someValue';` – magikMaker Mar 13 '18 at 14:52
  • 1
    You are lifesaver. This made my head hurt, while was upgrading from AngularJS app to Angular 7.x – Andris Aug 02 '19 at 10:35
14

Here is the best solution for this. (ANGULAR All Version)

Addressing solution: To set a default value for @Input variable. If no value passed to that input variable then It will take the default value.

I have provided solution for this kind of similar question. You can find the full solution from here

export class CarComponent implements OnInit {
  private _defaultCar: car = {
    // default isCar is true
    isCar: true,
    // default wheels  will be 4
    wheels: 4
  };

  @Input() newCar: car = {};

  constructor() {}

  ngOnInit(): void {

   // this will concate both the objects and the object declared later (ie.. ...this.newCar )
   // will overwrite the default value. ONLY AND ONLY IF DEFAULT VALUE IS PRESENT

    this.newCar = { ...this._defaultCar, ...this.newCar };
   //  console.log(this.newCar);
  }
}
Parth Developer
  • 1,371
  • 1
  • 13
  • 30