I'm trying to bind some data from a parent component to its child component and I keep getting the same type error.
I have a table full of cells with movie info and I want to open a modal with further details of a movie when its cell is clicked. This involves some API data fetching.
As such, I have my app-movie-list
template:
</table>
...
<tbody>
...
<tr *ngFor='let movie of movieList$ | async' (click)="selectMovie(movie.id)">
<td >{{ movie.rank }}</td>
<td >{{ movie.title }}</td>
...
</tr>
</tbody>
</table>
<app-movie-detail
[isDetailDisplayed]="isDetailDisplayed"
[movie]="(selectedMovie$ | async)"
...
>
</app-movie-detail>
When a cell is clicked, an API request is made in the component:
selectedMovie$!: Observable<MovieDetails>;
...
...
selectMovie(id: string) {
this.isDetailDisplayed = true;
this.selectedMovie$ = this.apiManager.fetchMovieById(id);
}
The API request in question:
fetchMovieById(id: string): Observable<MovieDetails> {
const endpoint = this.url "/api/movies/" id;
return this.http.get<MovieDetails>(endpoint);
}
And finally, in my app-movie-detail
I just have the input like so:
@Input() movie!: MovieDetails;
However, I keep getting the same compilation error:
Can anyone help me understand why I keep getting this type error? Thanks in advance.
CodePudding user response:
The fetchMovieById(id) probably returns MovieDetails | null
. I assume it fetches the data from a database. So either you handle the case of null in the parent component or you change your @Input() movie!: MovieDetails;
to @Input() movie!: MovieDetails | null;
CodePudding user response:
The observable selectedMovie$
will be suscribed to once the component is loaded due to the async pipe. Until the first request is actually performed you will get null.
You could add a filter to the request like
this.selectedMovie$ = this.apiManager.fetchMovieById(id).pipe(filter(value => !!value));
I think I'd not directly pass in the request-result into the databinding though. Instead I would use e.g. a BehaviorSubject/asObservable
combination and next()
the result of the fetch (still have the filter on that observable though or have a default/empty details value). That way you could use the info in different places as well if needed (a second async pipe would create another http request).