21

I'm creating a component. Since I like the Apache Wicket way of doing things, I am trying to emulate the IModel way of passing data. For that, to the child component I pass a model and callbacks which can pull out the relevant values, instead of calling a function to get the data upfront.

The problem is, that handling of the newly set model uses the callbacks. So if the model setter is called before callbacks are set, Angular crashes.
Workaround: postpone the actions that need the callback to ngAfterViewInit() or such.

In short:

  • How can I control the order in which the @Inputs are set?
  • Can I rely on the order in the source code?

Example: (Changing the order here seems to do the job)

@Input()
valueCallback: (item: any) => string
    = app => { throw new Error("valueCallback not yet defined."); };

@Input()
labelCallback: (item: ItemType) => string;

Template using that child component: (changing the order here doesn't change the order)

            <wu-checkboxes [groupName]="'includedApps'"
                           [options]="availableApps"
                           [valueCallback]="appsValueCallback"
                           [labelCallback]="appsLabelCallback"
            >

As I mention above, Angular2 seems to follow the order of the @Input class members and sets/calls them in that order. The question is, is that de-facto or de-jure? I don't want to rely on features that work just because it's currently coded that way. I don't know much about JavaScript reflection, so I can't tell whether this is going to work everywhere.

Ondra Žižka
  • 43,948
  • 41
  • 217
  • 277
  • You should use `ngOnInit`. It does exactly what you need: The docs say that "called after Angular first displays the data-bound properties and sets the directive/component's input properties. Called once, after the first ngOnChanges()." See https://angular.io/guide/lifecycle-hooks#lifecycle-sequence – Ruan Mendes Jul 25 '19 at 13:53

1 Answers1

18

You can use ngOnChanges() which is called every time an @Input() is updated by change detection. You can check within ngOnChanges whether all input values are already available and then execute your code. You need to take care yourself though, that subsequent updates don't trigger the function call again (in case this is not desired).

update

The order of bindings (value bindings and event bindings) is undefined in Angular2 and therefore you can't rely on a specific order.

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • 1
    Thanks for the tip. That's the approach I mean by 'ngAfterViewInit() or such' and would like to avoid. It requires quite some boilerplate code and it is, I'm afraid, error-prone. – Ondra Žižka Feb 22 '17 at 04:31
  • There is no specified order for inputs, therefore unlikely you can avoid it. – Günter Zöchbauer Feb 22 '17 at 05:07
  • Sounds right. How about putting it to the answer and I'll accept – Ondra Žižka Feb 22 '17 at 05:58
  • 2
    This issue is shown here: https://github.com/angular/angular/issues/40007. They agree that you should not rely on the order of those bindings – Samuel Thompson Jun 09 '22 at 12:43
  • although you shoudln't rely on the input binding order, it does matter if you put one before the other. i've noticed that the first input binding will initialize before the second one. – Elazar Zadiki Feb 20 '23 at 08:19