Why is Angular's SimpleChange.previousValue initially undefined?

Viewed 319

I have an Angular component with one property decorated with @Input. I explicitly initialized that property to a certain value. The first time the property changes to a new value, the corresponding SimpleChange.currentValue does have the correct new value, but SimpleChange.previousValue is undefined!

The component's code is this:

import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
import { TestService1Service } from '../test-service-1.service';

@Component({
  selector: 'app-input-test',
  templateUrl: './input-test.component.html',
  styleUrls: ['./input-test.component.css']
})
export class InputTestComponent implements OnChanges {

  constructor(public myTestSrv: TestService1Service) { }

  @Input() prop: string = 'Test 0';
  ngOnChanges(changes: SimpleChanges): void {
    const chng = changes['prop'];
    this.myTestSrv.addMsg(chng.previousValue + ' → ' + chng.currentValue);
  }
}

In the last line, where a message is added to myTestSrv, the first change to prop causes this message to be added:

undefined → Test 1

instead of

Test 0 → Test 1

although I verified that 'Test 0' was indeed assigned to prop before the first change occurred.

I couldn't find any question that addresses the same issue, and although I saw in one or two places (I forgot where exactly) something like "and because it's the first change, previousValue is undefined", there was no explanation, and it just doesn't make sense.
Being the first change doesn't imply an initial value of undefined, and if it has to be undefined then (logically) the first change must be from undefined to 'Test 0', and the second change from 'Test 0' to 'Test 1'.
What am I missing here?

1 Answers

Acording to documentation and source code as well for OnChanges lifecycle hook:

A lifecycle hook that is called when any data-bound property of a directive changes

So from my point of view the OnChanges doesn't care that you're initializing your property locally. He know about the changes which cames from the parent. (even if you put an initial value in component, and in the parent as well, the value from the parent will be displayed anyway).

And besides that, even if you provide an initial value from the parent, there's the 'first change' attribute which is set to true and the previousValue to undefined every time.

If we take a look at the source code we'll see:

const isFirstChange = this.unchangedInputs.has(property);
const previousValue = isFirstChange ? undefined : 
      this.getInputValue(property);

So, as I said above, the first time, every time previousValue will be undefined because of firstChange which is true

Related