Carolina
Carolina

Reputation: 250

@Input() value is undefined

I've created component which takes an @Input() value but I always get undefind. Here's my code:

parent.html

<added-item
      [minItemValueLength]="minItemValueLength"
      [maxItemValueLength]="maxItemValueLength"
      [listOfItems]="listOfItems"
  ></added-item>

children.ts

export class AddedItemComponent implements OnInit, OnChanges{

  @Input() minItemValueLength: number;
  @Input() maxItemValueLength: number;
  @Input() listOfItems: string[];

  ngOnInit() {
    console.log(this.minItemValueLength)      // return 3 
    console.log(this.listOfItems)             // return undefined
  }
}

parent.ts

export class LocationsTabComponent implements OnInit {
  listOfItems: string[];
  minItemValueLength = 3;
  maxItemValueLength = 15;

  public ngOnInit(): void {
    this.locationService.getLocations().subscribe((locations) => {
      this.getLocationsList();
      console.log(this.listOfItems)    // return Array(6)
    });
  }
  private getLocationsList() {
    this.listOfItems = this.locations.map((location: Location) => location.name);
    console.log(this.listOfItems)    // return Array(6)
  }
}

If I use ngOnChanges() in children than it at first output me:

data undefined and then:

data Array(6)

How can I get this value in onInit?

Would be really grateful for any help!

Upvotes: 0

Views: 930

Answers (3)

Basheer Kharoti
Basheer Kharoti

Reputation: 4302

Since your subscribing to the locations, you can use async to wait until the response is fully resolved or otherwise you have to implement OnChanges interface.

public async ngOnInit(): void {
await this.locationService.getLocations().toPromise().then((locations) => {
  this.getLocationsList();
  console.log(this.listOfItems)    // return Array(6)
});
}
private getLocationsList() {
  this.listOfItems = this.locations.map((location: Location) => location.name);
  console.log(this.listOfItems)    // return Array(6)
}

Upvotes: 1

Orel Eraki
Orel Eraki

Reputation: 12196

The value isn't always undefined only on the time the component is created, and this is because you passed as such.

Process:

  1. Parent is creating and ngOnInit is starting.
  2. ngOnInit has Observable\Promise\Async method, which means we're not waiting for the response, thus the value is still undefined.
  3. Child component is created and executing the ngOnInit. value still undefined.
  4. The Observable\Promise\Async method is now finally finished and custom callback you created now assigned the value, and the value is passed to the child component. So of course child ngOnInit will not accept it because the component was already created.

There are couple of solutions:

  1. Put *ngIf="listOfItems" on added-item.
  2. Decorate Parent as async ngOnInit, change: .subscribe to .toPromise e.g: await this.locationService.getLocations().toPromise..., now parent ngOnInit will wait for response.

Upvotes: 1

huan feng
huan feng

Reputation: 8623

This is because you assign

listOfItems = ...

in an async callback method.

If you want to detect the changes, you should implement onChanges interface and implement the corresponding hook method.

export class AddedItemComponent implements OnInit, OnChanges{

    @Input() minItemValueLength: number;
    @Input() maxItemValueLength: number;
    @Input() listOfItems: string[];

    ngOnInit() {
        console.log(this.minItemValueLength)      // return 3 
        console.log(this.listOfItems)             // return undefined
    }
    
    ngOnChanges(changes: SimpleChanges): void {
        if (changes.listOfItems) {
            console.log(this.listOfItems)
        }
    }

}

Upvotes: 2

Related Questions