Home > Enterprise >  Array shown as undefined in child component when using parametric route Angular
Array shown as undefined in child component when using parametric route Angular

Time:10-05

in a few words what I'm trying to do here is displaying some property of a specific item of the jobs array in a child component when navigating to /jobs/:id

Partent Component

export class HomeComponent implements OnInit {

  public jobs!: JobInterface[]

  constructor(
    private jobsService: JobsService
  ) {
  }

  ngOnInit() {
    this.getJobs()
  }


  getJobs(page = 1, filters = {city: 'Rome, Italy', level: ''}): void {
    this.jobsService.getJobs(page, filters)
      .subscribe((response) => {
        this.jobs = response.results.map(job => ({
            id: job.id,
            contents: job.contents,
            name: job.name,
            publication_date: job.publication_date,
            locations: job.locations,
            levels: job.levels,
            company: job.company

          })
        )
      })
  }

}

everything works on the routing perspective but into the child component the jobs array is shown as undefined making me unable to it for the desired item:

Child component

export class JobDetailsComponent implements OnInit {
  jobId : any
  @Input() jobs! : JobInterface[]
  selectedJob : any
  constructor(private ActivatedRoute : ActivatedRoute) { }

  ngOnInit(): void {
    this.jobId = this.ActivatedRoute.snapshot.paramMap.get('id')
    console.log(this.jobs)
    this.selectedJob = this.jobs.filter(this.jobId)

  }

}

Partent component's HTML

<app-search-bar (OutputFilters)="getFilteredResults($event)" ></app-search-bar>
<app-job-cards [jobs]="jobs"></app-job-cards>
<app-job-details [jobs]="jobs"></app-job-details>

what is the correct way to do this? What am I doing wrong here?

CodePudding user response:

Well, because the route changes, there's no jobs or job in the job-details component. Also, components render before data is retrieved.

You could add a flag to render component when data is ready and then you could move job-details component to job-cards component, and pass a single job from there via router, like so:

  • add a flag to render component when data is ready:
export class HomeComponent implements OnInit {
  dataReady:boolean = false;

// add after the response..
this.dataReady = true;

and in the template:

<app-job-cards *ngIf="dataReady" [jobs]="jobs"></app-job-cards>

and then:

  • remove app-job-details from home-component

pass job to job-details component via router from job-cards template:

<a mat-stroked-button routerLink="jobs/{{job.id}}" [state]="job">See More</a>

and then in the job-details component use it via history API:

ngOnInit(): void {
    this.selectedJob = window.history.state;
}

But that's a bad approach, and also the route would be empty when accessed directly.. you should decide what to do with that..

A better approach would be to store jobs in the jobs-service instead of home-component and passing them via parent/child, which will be shared between components, and add getJobs and getJobDetails methods that would get or fetch jobs, or find (rather than filter) a single job for job-details component (and maybe fetch a single job if you want details page to always have some data), which is a lot of refactoring to do..

  • Related