It appears that the ngOnInit function is being activated prior to receiving any data through the Input()

For a personal challenge, I am working on creating a website that showcases a list of League Of Legends champions. Users can click on the champion icons to access more details.

However, I am facing an issue where the champion details (specifically images) seem to display one click late.

https://i.sstatic.net/faco7.jpg When I clicked on the image of Kaisa, the image of the previous champ is displayed instead.

This is how I retrieve my data:

PARENT TS

export class ChampionListComponent implements OnInit {

  public displayPopup = false;
  public selectedChamp: Observable<any>;
  constructor(private store: Store<LolState>) { }

  ngOnInit() {
    this.selectedChamp = this.store.pipe(select(selectChampDetails));
  }

  selectChamp(name) {
    this.displayPopup = true;
    this.store.dispatch(new GetChampionsDetails(name));
  }

PARENT HTML

<ul class="champion_list">
  <li (click)="selectChamp(champion.key)">
    ...List of champions
  </li>
</ul>

<ng-container *ngIf="displayPopup">
  <app-champion-details *ngIf="selectedChamp | async as champ" [selectedChamp]="champ"></app-champion-details>
</ng-container>

CHILD TS

export class ChampionDetailsComponent implements OnInit {

  @Input() selectedChamp: any;
  public skins: Array<{path: string}>;
  constructor() { }

  ngOnInit(): void {
    if (this.selectedChamp.skins) {
      this.skins = this.selectedChamp.skins.map(skin => {
        return {path: 'LINK'}
      })
    }
  }

CHILD HTML

<section *ngIf="selectedChamp as Champ" class="container">
    <carousel cellWidth="100%" cellToShow="1" [loop]="true" [images]="skins"></carousel>
    <div class="champ_infos">
        <h2>{{Champ.id | titlecase}}</h2>
        <h3>{{Champ.title | titlecase}}</h3>
        <article>
            {{Champ.lore}}
        </article>
    </div>
</section>

The information is retrieved from my service, which is called by an effect that dispatches actions to store data in my state. The data is correctly stored in my state, as confirmed by console.log displaying the correct information in the parent component.

It seems like Angular may be trying to execute the map function before fully receiving the input?

Edit: I replaced

*ngIf="selectedChamp as Champ"
with *ngIf="skins" in the child component to ensure the content is only shown once fully loaded. You can see the result in the provided gif.

https://i.sstatic.net/cs9hJ.gif

(I have omitted some irrelevant code for clarity. If there are typos or unknown variables, please disregard them as they are not related to the issue)

Answer №1

When passing inputs to a child component, the new value can be accessed in the OnChanges lifecycle hook. Here is an example implementation:

ngOnChanges(changes: SimpleChanges) {
if(changes && this.selectedChamp && this.selectedChamp.skins){
  this.skins = this.selectedChamp.skins.map(skin => {
        return {path: 'LINK'}
      })
    }
 }

Within this lifecycle, every time the input data is updated in the parent component, it will be reflected in the child component.

Answer №2

Here is the issue at hand:

<ng-container *ngIf="displayPopup">
  <app-champion-details *ngIf="selectedChamp | async as champ" [selectedChamp]="champ"></app-champion-details>
</ng-container>

The problem arises when the displayPopup becomes true, and the champion-details are shown because the selectedChamp Observable already has a value. This can lead to an outdated state being displayed if the component is opened for the second time. Although a new value eventually arrives asynchronously, the component has already initialized, causing the old state to be displayed.

A suggested solution would be to try a different approach. Upon closing the details component, clear out the selectedChamp in the store. By doing this, the ng-container is no longer needed, and you can rely solely on the

*ngIf="selectedChamp | async as champ"
to display the details component.

  <app-champion-details *ngIf="selectedChamp | async as champ" [selectedChamp]="champ"></app-champion-details>

An example implementation inside the closeChampionDetails method could look like this:

public closeChampionDetails() {
  this.store.dispatch(new ClearSelectedChampion());
}

Answer №3

To avoid any issues with the input selectedChamp being called before receiving the necessary data in the child component, you can add a simple check like this:

ngOnInit(): void {
    if (this.selectedChamp && this.selectedChamp.skins) {
        this.skins = this.selectedChamp.skins.map(skin => {
            return { path: 'LINK' }
        })
    }
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Loop through an icon in Angular 2 until a specific condition is met

Currently, I am in the process of developing my portfolio website using Angular 2 and I want to incorporate a skill matrix. For testing purposes, I am using a square provided by font-awesome as an example. <tbody *ngFor="let skill of skills"> <tr ...

Ensure that the method is passed a negative number -1 instead of the literal number 1 from an HTML error

This is an example of my HTML code: <button (mousedown)="onMouseDown($event, -1)"></button> Here is the TypeScript code for handling the mouse down event: onMouseDown(e: MouseEvent, direction: 1|-1) { this.compute.emit(direction); ...

When utilizing Angular 2, this message is triggered when a function is invoked from the Observable

One of my services is set up like this: @Injectable() export class DataService { constructor(protected url: string) { } private handleError(error: Response) { console.log(this.url); return Observable.throw(new AppError(error)); ...

Encountered a problem during the installation of Angular 4

Recently delving into angular, my journey began with the installation of node js on my machine. Following this link, I attempted to install angular, only to be met with the following error: gyp verb check python, inspecting if Python executable "python" i ...

Angular mat-select is having difficulty displaying options correctly on mobile devices or devices with narrow widths

In my Angular project, I've encountered an issue with mat-select when viewing options on mobile or low-resolution screens. While the options are still displayed, the text is mysteriously missing. I attempted to set the max width of the mat-option, but ...

Ways to transfer JavaScript arguments to CSS style

Currently, I am developing a web service using Angular and Spring Boot. In this project, I have implemented cdkDrag functionality to allow users to place images in specific locations within the workspace. My goal is to maintain the placement of these image ...

Using Typescript with Protractor for Dropdown Menus

As a newcomer to Protractor, I am looking to automate the selection of a dropdown. While I have some knowledge in JavaScript, I am currently working with typescript. Can someone advise me on how to select the dropdown option based on the text provided? Fo ...

Transferring information through parent-child components via onChange

I have a question regarding data binding. In my project, I have a parent component and two child components: Parent: directives: [firstChild,secondChild], template:' <first-child [showList]="showList" (emitShowList)="getShowList($event)"& ...

Loading the value of a Subject variable in an Angular 2 application using Typescript

I am currently developing an Angular2 application where I am loading data from a service into my component as a subject. public type1Choisi: any; constructor( public formeService: FormeService, ...) { this.formeService._type1.subscribe(type1 => ...

Utilize Angular to inject an input from a component directly into the header of my application

I am looking to customize my Pages by injecting various components from different Pages/Components into the header. Specifically, I want to inject an Input search field from my content-component into the header Component. I initially attempted to use ng-Co ...

Issues with loading image assets on GitHub Pages after deploying in production with Angular2, Angular-cli, and Webpack

This is NOT a repeated query: This particular issue presents the problem, but it pertains to a project not built with angular-cli like mine does, hence a webpack.config file is absent. While my described dilemma involves accurately configuring the base_u ...

Toggling multiple ions simultaneously does not function independently

I encountered a problem while working on an ionic app. I needed to have individual control over toggle switches, but my current code toggles all switches at once whenever one switch is tapped. Is there a way to fix this and manage each toggle switch separa ...

Testing onClick using Jest when it is not a callback function in props

I have discovered various ways to utilize mock functions in jest for spying on callback functions passed down to a component, but I have not found any information on testing a simple onClick function defined within the same component. Here is an example f ...

Resolving naming conflicts in Angular templates: what's the solution?

Within my application, I have created two essential components: JokesList Joke The JokesListComponent is structured as follows: template: <app-joke *ngFor="let joke of jokes" [joke]="joke"></app-joke> @Component({ sel ...

Creating data types from the name of the route in vue-router route[x]

I am attempting to generate route names based on the routes defined in the Vue Router. My goal is to utilize a helper function called findRouteByName() to locate a specific route. However, I encountered an issue when trying to define the parameters of the ...

Display a div above the Kendo for Angular Dialog

Looking at this StackBlitz example, there is a Kendo for Angular Dialog that contains a div with the CSS property position:absolute. The goal is to display this div on top of the dialog itself, rather than inside it, while ensuring that the dialog does n ...

Tips for adding Google Tag Manager to a popup within a Chrome extension?

I have successfully developed a chrome extension. In the popup HTML, I added the Google Tag Manager script and a noscript iframe like this: <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>Signals< ...

Having trouble getting @types/express-session to function properly. Any suggestions on how to fix it?

My web-app backend is built with TypeScript and I've integrated express-session. Despite having @types/express and @types/express-session, I continue to encounter type errors that say: Property 'session' does not exist on type 'Request ...

Tips for showing a DialogBox when a blur event occurs and avoiding the re-firing of onBlur when using the DialogBox

Using React and Material UI: In the code snippet provided below, there is a table with TextFields in one of its columns. When a TextField triggers an onBlur/focusOut event, it calls the validateItem() method that sends a server request to validate the ite ...

Using Firebase's REST API to send a PATCH request

Greetings, I am currently working on an Angular application that utilizes Firebase. I need to update a record in my database and I am using the REST API for this purpose: this.http.patch(fireBaseConfigDBEndpointCloudReference + this.logIn.getUser().valu ...