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
fromhome-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..