【问题标题】:Cannot read properties of undefined (reading 'page') in angular无法以角度读取未定义(读取“页面”)的属性
【发布时间】:2021-10-07 20:01:25
【问题描述】:

我遇到了这个错误,我无法完成它。console error

我不知道为什么它无法读取未定义的属性(读取“页面”),并且我需要一些帮助来尝试修复它,我不知道如何检查到底是什么不工作。以及页面刷新返回相同的错误

listc-component-helper.service.ts

import {  Injectable, ViewChild } from '@angular/core';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
import { merge, Observable, of } from 'rxjs';
import { catchError, map, switchMap } from 'rxjs/operators';
import { Filter } from '../core/models/filter';
import { PaginatedResponse } from '../core/models/paginated-response';
import { GuiUtilsService } from '../core/services/gui-utils.service';
import { Constants } from './constants';
import { SubscribeHelper } from './subscribe-helper';

@Injectable()
export abstract class ListComponentHelper extends SubscribeHelper {
    displayedColumns: string[];
    data: any[];
    resultsLength = 0;
    pageSize: number = Constants.DEFAULT_PAGESIZE;
    pageSizeOptions: number[] = Constants.DEFAULT_PAGESIZE_OPTIONS;

    currentFilter: Filter;

    @ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
    @ViewChild(MatSort, { static: true }) sort: MatSort;

    /**
     * Returns the current sort that the user has chosen by clicking on the table header columns.
     */
    protected abstract getCurrentSort(): number;

    /**
     * Method that will be used to delete an item.
     * @param id Id that can be used in case of an number id.
     * @param userId stringId can be used in case of a string id.
     */
    protected abstract deleteItem(id: number, stringId?: string): Observable<any>;

    /**
     * The method that will be used to fetch data from the API.
     */
    protected abstract getData(pageSize: number, pageIndex: number, sortMode: number, filter?: Filter): Observable<PaginatedResponse>;

    constructor(protected guiUtils: GuiUtilsService) {
        super();
    }

    /** Must be called on onInit because it has mat paginator and mat sort that are only available at that time. */
    protected initBaseComponent(): void {

        if (this.sort) {
            // If the user changes the sort order, reset back to the first page.
         
               this.addSubscription(this.sort.sortChange.subscribe(() => this.paginator.pageIndex = 0));
        }
      
        const observable$ = this.sort ? merge(this.sort.sortChange, this.paginator.page) : this.paginator.page.asObservable();
        
        this.addSubscription(observable$
           
            .pipe(
                
                switchMap(() => {
                    this.pageSize = this.paginator.pageSize ? this.paginator.pageSize : this.pageSize;

                    setTimeout(() => this.guiUtils.showLoading());
                    return this.getData(this.pageSize, this.paginator.pageIndex + 1, this.getCurrentSort(), this.currentFilter);
                }),
                map(data => {
                    // Flip flag to show that loading has finished.
                    setTimeout(() => this.guiUtils.hideLoading());
                    this.resultsLength = data.totalResults;

                    return data.results;
                }),
                catchError(error => {
                    setTimeout(() => this.guiUtils.hideLoading());
                    return of([]);
                })
            ).subscribe(data => this.data = data));
    }

    protected refreshData(): any {
        this.guiUtils.showLoading();

        this.addSubscription(this.getData(this.pageSize, this.paginator.pageIndex + 1, this.getCurrentSort(), this.currentFilter).pipe(
            map(data => {
                setTimeout(() => this.guiUtils.hideLoading());
                this.resultsLength = data.totalResults;

                return data.results;
            }),
            catchError(error => {
                setTimeout(() => this.guiUtils.hideLoading());
                return of([]);
            })
        ).subscribe(data => this.data = data));
    }

    /**
     * Will delete the entity with the delete function provided in the constructor.
     * @param id The entity id.
     * @param name The name of the entity to display to the user.
     * @param event The event to stop propagation.
     * @param stringId Id that can be used in case of a string id (like the user id).
     */
    protected deleteEntity(id: number, name: string, event: any, stringId?: string): any {
        event.stopPropagation();

        this.addSubscription(this.guiUtils.showGenericDeleteDialog(name).subscribe(confirmed => {
            if (confirmed) {
                this.guiUtils.showLoading();

                this.addSubscription(this.deleteItem(id, stringId).subscribe(() => {
                    this.refreshData();
                    
                }));
            }
        }));
    }
    
}

istoric-comenzi.component.ts

import { Component, OnInit, OnDestroy } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { Filter } from 'src/app/core/models/filter';
import { PaginatedResponse } from 'src/app/core/models/paginated-response';
import { ListComponentHelper } from 'src/app/utils/list-component-helper.service';
import { Observable, EMPTY } from 'rxjs';
import { ActivatedRoute } from '@angular/router';
import { GuiUtilsService } from 'src/app/core/services/gui-utils.service';
import { OrderService } from './services/order.service';
import { HydraOrderHistoryResponse } from '../servic/hydra-order-history';
import { HydraOrderHistoryItem } from '../servic/hydra-order-history';
import * as moment from 'moment';
import { HydraOrderDetails } from '../servic/hydra-order-details';
import { ORDER_HISTORY_FILTER } from 'src/app/utils/constants';



@Component({
  selector: 'app-istoric-comenzi',
  templateUrl: './istoric-comenzi.component.html',
  styleUrls: ['./istoric-comenzi.component.scss']
})
export class IstoricComenziComponent extends ListComponentHelper implements OnInit, OnDestroy {
  public moment = moment;
  public orderDetails: HydraOrderDetails = null;
  public selectedOrder: HydraOrderHistoryItem = null;
  private orderFilter: Filter = JSON.parse(JSON.stringify(ORDER_HISTORY_FILTER));

  protected getCurrentSort(): number {
    return 0;
  }

  protected deleteItem( ): Observable<any> {
    return EMPTY;
  }

  protected getData(pageSize: number, pageIndex: number, sortMode: number, filter?: Filter): Observable<PaginatedResponse> {
    this.selectedOrder = null;
    return this.orderService.getHistory(pageSize, pageIndex, sortMode, filter);
  }

  constructor(
    public translate: TranslateService,
    private route: ActivatedRoute,
    protected guiUtils: GuiUtilsService,
    private orderService: OrderService,
   
    ) {
    super(guiUtils);

    this.displayedColumns = ['orderNo','orderDate', 'userName', 'date', 'deliveryAddress', 'billUrl', 'orderStatus'];
  }

  ngOnInit() {
    this.addSubscription(this.route.data.subscribe((data: {
      history: HydraOrderHistoryResponse,
    }) => {
      this.data = data.history.results;
      this.resultsLength = data.history.totalResults;
    }));
    this.initBaseComponent();
    
  }

  getDate(date: Date): string {
    return moment(date).format('DD/MM/YY');
  }
  getTime(date: Date): string {
    return moment(date).format('HH:mm');
  }

  selectOrder(order: HydraOrderHistoryItem) {
    this.guiUtils.showLoading();

    this.addSubscription(this.orderService.getDetails(order.orderId).subscribe((orderDetails: HydraOrderDetails) => {
      this.orderDetails = orderDetails;
      this.selectedOrder = order;
      this.guiUtils.hideLoading();
    }));
  }

  

  

  

  

  
}

【问题讨论】:

  • 您需要等待视图初始化后才能访问您的@ViewChild。只需在 ngAfterViewInit() {} 中访问它们
  • 你能更明确一点吗?并告诉我它是如何在我的代码中完成的;(?
  • 如果它确实有效,请将您的问题的标题更改为:无法从基类或其他内容中访问 ViewChild 属性,因为您的标题并未表明您的问题。

标签: angular


【解决方案1】:

除非视图已初始化(角度称为 ngAfterViewInit() 挂钩方法),否则您无法访问您的 @ViewChild,因此您必须在 ngAfterViewInit() 中调用 initBaseComponent()

@Component({
  selector: 'app-istoric-comenzi',
  templateUrl: './istoric-comenzi.component.html',
  styleUrls: ['./istoric-comenzi.component.scss']
})
export class IstoricComenziComponent extends ListComponentHelper implements OnInit, OnDestroy, AfterViewInit {
.
.
.

 ngAfterViewInit(){
   this.initBaseComponent();
 }
.
.
. // rest of your code
}

编辑: 上面的答案将在父组件中工作,但在您的情况下,您应该在 IstoricComenziComponent 中获取 ViewChild 属性并将它们传递给基类。 我会为你写一个解决方案: 在 IstoricComenziComponent

中添加属性
@Component({
  selector: 'app-istoric-comenzi',
  templateUrl: './istoric-comenzi.component.html',
  styleUrls: ['./istoric-comenzi.component.scss']
})
export class IstoricComenziComponent extends ListComponentHelper implements OnInit, OnDestroy, afterViewInit {
    @ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
    @ViewChild(MatSort, { static: true }) sort: MatSort;


 ngAfterViewInit(){
   this.initBaseComponent(paginator, sort);
 }
}

listc-component-helper.service.ts 应该是这样的:

@Injectable()
export abstract class ListComponentHelper extends SubscribeHelper {
paginator: MatPaginator;
sort: MatSort;
.
.
.

  protected initBaseComponent(paginator: MatPaginator, sort: MatSort): void 
  {
     this.paginator = paginator;
     this.sort = sort;
    // the rest of your code
  }
}

我测试了这个解决方案,它可以正常工作。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2022-01-08
  • 2015-08-10
  • 2019-04-28
  • 2021-08-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-30
相关资源
最近更新 更多