DEV Community

Angular: Setters vs ngOnChanges - which one is better?

Giancarlo Buomprisco on July 31, 2020

This post was originally published on Angular Bites Getting notified about an Angular component's property changes is normally done in 2 ways: ...
Collapse
 
bo profile image
Bo Vandersteene
  ngOnChanges({ name, email }: SimpleChanges) {
    const username = name.currentValue || email.currentValue;
    this.username$.next(username);
  } 
Enter fullscreen mode Exit fullscreen mode

If you take this code in consideration, you need to pay attention, that both values are changed on the same time. If the ngOnChanges is called 2 times for each value, than this one can give some unwanted sideEffects.

Collapse
 
gc_psk profile image
Giancarlo Buomprisco

Hi! do you mean that name or email could be undefined? TBH I'd never ship this to production - just needed a short example with multiple inputs 😅

Collapse
 
bo profile image
Bo Vandersteene • Edited

Ok so if you have a component that uses your code like this

<my-component [email]="email$ | async" 
                               [username]="username$ | async"> </my-component>

If the input of the observables look like this

email$    = -E----
username$  =  ----U--

Then the ngOnChanges will be called first with only email and then with only username so one of the two is undefined. Only the values that are changed are submitted in the SimpleChanges

Thread Thread
 
abelardoit profile image
abelardoit

And what's the solution to avoid this situation, please? Would you opt by adding a setter to the property?

Thread Thread
 
bo profile image
Bo Vandersteene

It depends what do you want to achieve with this function.
Like I read this it should only take the email into account if the name is empty so something like this:

 ngOnChanges({ name, email }: SimpleChanges) {
    const username = name?.currentValue ?? this.name ?? email?currentValue ?? this.email
    this.username$.next(username);
  }
Enter fullscreen mode Exit fullscreen mode
Thread Thread
 
abelardoit profile image
abelardoit

Thanks for replying asap! Best regards.

Collapse
 
hassam7 profile image
Hassam Ali

I tend to avoid setters with the inputs if the inputs have dependency on other inputs because then the order inputs to the components matter.

@Component({...})
class Component {
  @Input()
  url: Url;
  @Input()
  set users(users: Array<User>) {
    this._users = users.map((user) => {
      return user.avatar = this.url.baseUrl + user.avatar;
    });
  }
  private _users: Array<User>;
}
<component [url]="'someurl'" [users]=users /> //will work fine
<component [users]=users [url]="'someurl'" /> //will not work fine
Enter fullscreen mode Exit fullscreen mode

see this link for further details: medium.com/generic-ui/a-deep-dive-...

Collapse
 
glebirovich profile image
Gleb Irovich

Surprisingly we had this discussion as well recently. We came up with using setters as a preferred option. I don’t see any major disadvantages of that approach. 👍

Collapse
 
estuardo_wyss_a314cbf341b profile image
Estuardo Wyss • Edited

Try this approach. Works fine for me.

ngOnChanges(changes: SimpleChanges): void {
     for (const propName in changes) {
        if (propName == 'invoiceSelected') {
                this.doubleEntryService.invoiceSelected = this.invoiceSelected;
                this.setInvoiceValues();
            }

            if (propName == 'verifyAI') {
                if(this.verifyAI){
                    this.ikcValidateinvoiceComponents();
                }
            }
    }
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
penguintheorem profile image
Attilio Urbani

Hi!

i prefer the first approach too (setter). I think that the code is definitely more clean than using the hook. Thanks for sharing your tip!

Collapse
 
abelardoit profile image
abelardoit

Hi there,
Why did you affirm that (to receive all the inputs at once) is (sometimes) a sign of a code-smell?
What's wrong by passing several inputs at once?
Thanks! Brs.

Collapse
 
ffex profile image
ffex

I'm curious too! :)

Collapse
 
constjs profile image
Piotr Lewandowski

Great and short summary :)
Have you considered performance differences with default change detection strategy?

Collapse
 
gc_psk profile image
Giancarlo Buomprisco • Edited

I haven't - but even then I'd be surprised if there were any noticeable differences :)