-1

i'm getting this error and i can t get it done.console error

i don't know why it cannot read properties of undefined (reading 'page') and i need some help trying to fix it as well i don't know how to check exactly what is not working. as well page refresh return same 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();
    }));
  }

  

  

  

  

  
}
  • You need to wait for the view to be initialized before you can access your @ViewChild. Just access them inside ngAfterViewInit() {} – msleiman Oct 07 '21 at 10:06
  • can u be more explicit please ? and show me how it is done in my code ;( ? – Tudor Costea Oct 07 '21 at 10:30
  • If it does work, please change the title of your question to: can not access a ViewChild property form a base class or something because your title is not indicating your problem. – msleiman Oct 07 '21 at 11:42

1 Answers1

0

You can't access your @ViewChild unless the view is initialized (angular called ngAfterViewInit() hook method), so you must call initBaseComponent() inside ngAfterViewInit().

@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
}

Edit: The answer above will work inside a parent component, but in your case you should get the ViewChild properties inside IstoricComenziComponent and pass them to the base class. I will write a solution for you: Add the properties inside 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);
 }
}

And listc-component-helper.service.ts should be like:

@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
  }
}

I tested this solution, it will work fine.

msleiman
  • 146
  • 5