Я разрабатываю таблицу с Material Angular, чтобы показать список пользователей из базы данных Postgres, и я сталкиваюсь с этой проблемой:
Чтобы отобразить результаты в таблице, я загружаю их с нумерацией страниц из Spring Boot, поэтому URL выглядит примерно так: http://localhost:8080/user/page?_page=1&_pageSize=5&_sortDir=ASC
Я сделал сервис в Angular, чтобы получить его от бэкэнда, но вместо правильных параметров я получаю «неопределенные» параметры.
Мой user-service.ts :
const PATH = `${environment.url_base}/user`;
@Injectable({
providedIn: 'root'
})
export class UsersService implements IPaginationService<User> {
constructor(
private http: HttpClient
) {}
public getPage(pagRequest: PaginationDataRequest) :
Observable<PageData<User>> {
return this.http.get<PageData<User>>(PATH + '/page', {
params: pagRequest.toHttpParams()
});
}
user.component.ts
@Component({
selector: 'app-user',
templateUrl: './user.component.html',
styleUrls: ['./user.component.scss']
})
export class UserComponent implements OnInit {
public formFilter: FormGroup;
public dataSource: DataSourceBase<User>;
public codIdUsuarioFilter: string[] = [];
public selectionUsuarios = new SelectionModel<string>(true, []);
public pageSizes = [15, 25, 50, 100];
private subscriptions: Subscription[] = [];
@ViewChild(MatSort) sort: MatSort;
@ViewChild(MatPaginator) paginator: MatPaginator;
public columns = [
{columnDef: 'id', header: 'ID', cell: (row: User) => `${row.id}`, flex: 10, sortable: true},
{columnDef: 'name', header: 'Nombre', cell: (row: User) => row.name, sortable: true},
{columnDef: 'surname', header: 'Apellidos', cell: (row: User) => row.surname, sortable: true},
{columnDef: 'email', header: 'Email', cell: (row: User) => row.email, sortable: false},
{columnDef: 'incorporation_date', header: 'Incorporación', cell: (row: User) => row.incorporation_date, sortable: true}
];
public visibleColumns = ['id', 'name', 'surname', 'email', 'incorporation_date'];
public actions: RowActions<User>[] = [
{ icon: 'edit', action: (user: User) => {
this.router.navigateByUrl(`/user/${user.id}`);
}, color: 'primary'}
];
public buttonsHead: RowActions<any>[] = [];
constructor(private formBuilder: FormBuilder,
private route: ActivatedRoute,
private usersService: UsersService,
private router: Router,
private sessionService: SessionService)
{
this.dataSource = new UsersDataSource(usersService);
}
ngOnInit() {
this.formFilter = this.formBuilder.group({
id: ['', ],
name: ['', Validators.minLength(4)],
});
}
matcher = new MyErrorStateMatcher();
searchCodIdUsuario: string[] = [];
removeCodIdUsuario(codIdUsuarios: any): void {
const index = this.codIdUsuarioFilter.indexOf(codIdUsuarios);
if (index >= 0) {
this.codIdUsuarioFilter.splice(index, 1);
}
}
clean() {
this.formFilter.reset();
this.codIdUsuarioFilter = [];
this.refresh();
}
private validateForm() : boolean {
if(this.formFilter.get("name").invalid){
return false;
} else {
return true;
}
}
refresh() {
if (!this.validateForm()) {
return;
}
this.paginator.pageIndex = 0;
this.loadPage();
}
loadPage() {
this.formFilter.get('id').setValue(this.codIdUsuarioFilter);
let pagRequest = new PaginationDataRequest({
page: this.paginator.pageIndex + 1,
pageSize: this.paginator.pageSize,
sortFields: [this.sort.active || 'id'],
sortDir: this.sort.direction === 'desc' ? 'DESC' : 'ASC',
filter: this.formFilter.value
});
this.dataSource.loadPage(pagRequest);
}
ngAfterViewInit() {
this.preparePagedTable();
}
ngOnDestroy(): void {
this.subscriptions.forEach(sub => {
sub.unsubscribe();
});
}
private preparePagedTable() {
if (this.subscriptions.length === 0) {
// reset the paginator after sorting
let sub = this.sort.sortChange.subscribe(() => this.paginator.pageIndex = 0);
this.subscriptions.push(sub);
sub = merge(this.sort.sortChange, this.paginator.page).subscribe(() => this.loadPage());
this.subscriptions.push(sub);
sub = this.dataSource.requestReloadEvents.subscribe(() => this.refresh());
this.subscriptions.push(sub);
}
}
}
export class MyErrorStateMatcher implements ErrorStateMatcher {
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
const isSubmitted = form && form.submitted;
return !!(control && control.invalid && (control.dirty || control.touched || isSubmitted));
}
}
class UsersDataSource extends DataSourceBase<User> {
constructor(usersService: IPaginationService<User>) {
super(usersService);
}
}
IPaginationService
export type FilterObject = { [param: string]: string | string[]; };
export class PaginationDataRequest {
page: number;
pageSize: number;
sortFields: string[];
sortDir: 'ASC' | 'DESC';
filter?: FilterObject;
public toHttpParams() : HttpParams {
let params = new HttpParams({ fromObject: this.filter });
params = params.append("_page", `${this.page}`);
params = params.append("_pageSize", `${this.pageSize}`);
params = params.append("_sortDir", `${this.sortDir}`);
this.sortFields.forEach(fieldName => {
params = params.append("_sortFields", fieldName);
});
return params;
}
constructor(fields: Partial<PaginationDataRequest>) {
Object.assign(this, fields);
}
}
export class PageData<T> {
content: T[];
total: number;
constructor(content = [], total = 0) {
this.content = content;
this.total = total;
}
}
export interface IPaginationService<T> {
getPage(pagRequest: PaginationDataRequest) : Observable<PageData<T>>;
}
Я использую пересчитываемый MatTable, поэтому мне просто нужно дать ему некоторые параметры, такие как dataSource и так далее. Дело в том, что при загрузке таблицы отображаются столбцы и нумерация страниц, но при монтировании петиции GET происходит сбой, поскольку в некотором роде она получает «неопределенный».
Ошибка
ERROR TypeError: Cannot read property 'sortChange' of undefined
at UserComponent.push../src/app/ui/user/user.component.ts.UserComponent.preparePagedTable (main.js:3298)
at UserComponent.push../src/app/ui/user/user.component.ts.UserComponent.ngAfterViewInit (main.js:3287)
at callProviderLifecycles (vendor.js:83140)
at callElementProvidersLifecycles (vendor.js:83114)
at callLifecycleHooksChildrenFirst (vendor.js:83104)
at checkAndUpdateView (vendor.js:84040)
at callViewAction (vendor.js:84272)
at execEmbeddedViewsAction (vendor.js:84235)
at checkAndUpdateView (vendor.js:84032)
at callViewAction (vendor.js:84272)
ERROR TypeError: Cannot read property 'forEach' of undefined
at PaginationDataRequest.push../src/app/domain/pagination.ts.PaginationDataRequest.toHttpParams (main.js:1115)
at UsersService.push../src/app/services/users-service.ts.UsersService.getPage (main.js:1921)
at UsersDataSource.push../src/app/common/pagination-utils.ts.DataSourceBase.loadPage (main.js:993)
at PagedTableComponent.push../src/app/ui/shared/paged-table/paged-table.component.ts.PagedTableComponent.loadPage (main.js:2975)
at PagedTableComponent.push../src/app/ui/shared/paged-table/paged-table.component.ts.PagedTableComponent.refresh (main.js:2972)
at SafeSubscriber._next (main.js:2960)
at SafeSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.SafeSubscriber.__tryOrUnsub (vendor.js:173179)
at SafeSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.SafeSubscriber.next (vendor.js:173117)
at Subscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber._next (vendor.js:173061)
at Subscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next (vendor.js:173038)
defaultErrorLogger @ vendor.js:76536