Hello fellow programmers. Just for context, this is sort of like an IMDb-inspired web application that I'm trying to build for the first time in Angular.
I am currently trying to make my pagination component into a reusable one as I was previously mostly just copying and pasting code into other components that required pagination.
So for my main MoviesComponent
, it will show movies in a grid-like view and at the bottom, we will have pagination for these movies:
movies.component.html
...
<app-pagination
[maxPage]="maxPage"
[page]="page"
[updateItemsList]="fetchMovieList"
>
movies.component.ts
import { Component, OnInit } from '@angular/core';
import { FormControl } from '@angular/forms';
import { WebService } from '../web.service';
import { map, startWith } from 'rxjs/operators';
import { MatDialog } from '@angular/material/dialog';
import { FilterDialogComponent } from './filter-dialog/filter-dialog.component';
import { Movie } from '../interfaces/movie';
@Component({
selector: 'app-movies',
templateUrl: './movies.component.html',
styleUrls: ['./movies.component.css']
})
export class MoviesComponent implements OnInit {
movies_list: any;
page: number = 1;
maxPage: number = 0;;
constructor(
private webService: WebService,
public filterDialog: MatDialog
) { }
ngOnInit(){
if (sessionStorage['page']) {
this.page = Number(sessionStorage['page']);
}
this.fetchMovieList();
this.webService.getMaxPage().subscribe((data: any) => {
this.maxPage = data['max_page'];
});
}
fetchMovieList(): void{
this.webService
.getMovies(this.page)
.subscribe((data: any) => {
this.movies_list = data;
});
}
I am trying to update the movies_list
list (shown above) whenever a user clicks on one of the next, previous, last, first buttons to update my pagination, which I am trying to achieve by passing a function into my PaginationComponent
class like so:
pagination.component.ts
import { Component, Input, OnInit } from '@angular/core';
import { WebService } from '../web.service';
@Component({
selector: 'app-pagination',
templateUrl: './pagination.component.html',
styleUrls: ['./pagination.component.css']
})
export class PaginationComponent implements OnInit {
@Input() maxPage: number = 0;
@Input() page: number = 1;
@Input() updateItemsList!: () => void;
constructor(
) { }
ngOnInit(): void {
}
updatePagination(): any {
sessionStorage['page'] = this.page;
this.updateItemsList()
}
getPageArray() {
if (this.maxPage > 5) {
if (this.page > 3 && this.page <= (this.maxPage - 2)) {
return [...Array(5).keys()].map(x => x (this.page - 2));
} else if (this.page > (this.maxPage - 2)) {
return [...Array(5).keys()].map(x => x (this.maxPage - 4));
} else {
return [...Array(5).keys()].map(x => x 1);
}
} else {
return [...Array(this.maxPage).keys()].map(x => x 1);
}
}
firstPage() {
this.page = 1;
this.updatePagination()
}
previousPage() {
if (this.page > 1) {
this.page--;
this.updatePagination()
}
}
goToPage(page: number) {
this.page = page;
this.updatePagination()
}
nextPage() {
if (this.page < this.maxPage) {
this.page ;
this.updatePagination()
}
}
lastPage() {
this.page = this.maxPage;
this.updatePagination()
}
}
pagination.component.html
<p >Current Page: {{ page }}</p>
<section>
<div >
<button
mat-stroked-button
matToolTipcolor="primary"
matTooltip="Go to first page"
(click)="firstPage()">
<<
</button>
<button
mat-stroked-button
color="primary"
matTooltip="Go to previous page"
(click)="previousPage()">
<
</button>
<div *ngFor="let i of getPageArray()">
<button mat-raised-button color="primary" (click)="goToPage(i)">{{i}}</button>
</div>
<button
mat-stroked-button
color="primary"
matTooltip="Go to next page"
(click)="nextPage()">
>
</button>
<button
mat-stroked-button
color="primary"
matTooltip="Go to last page"
(click)="lastPage()">
>>
</button>
</div>
</section>
Unfortunately, whenever I click on one of these buttons. I get a
ERROR TypeError: Cannot read properties of undefined (reading 'getMovies')
I am nearly sure it's something to do with the way I am calling the function in the wrong scope as if I add webService: WebService
in the constructor params in PaginationComponent
the error goes away but nothing quite happens when I click the buttons. I come from a React FP background so I might be getting some OOP concepts or angular data-binding wrong.
Any help would be appreciated :)
P.S. Let me know how I did on my first StackOverflow post. I hope I explained everything clearly and don't want to annoy anyone on a Friday afternoon. Thanks guys for your help! I look forward to hearing your feedback.
CodePudding user response:
use an output from the child to trigger a function in the parent, don't pass a function to a child for it to call.
change the following in pagination component:
@Output() updateItemsList = new EventEmitter<number>();
updatePagination(): any {
sessionStorage['page'] = this.page;
this.updateItemsList.emit(this.page);
}
in parent template, bind to it:
<app-pagination
[maxPage]="maxPage"
[page]="page"
(updateItemsList)="fetchMovieList($event)"
>
in parent:
ngOnInit(){
...
this.fetchMovieList(this.page);
...
}
fetchMovieList(page: number): void{
this.webService
.getMovies(page)
.subscribe((data: any) => {
this.movies_list = data;
});
}