Encountering an error when attempting to access undefined property while using a method as a callback

Exploring OOP and angular is new to me. I am currently trying to implement a reusable table with pagination that triggers an API request when the page changes (pagination within the table component).

The issue arises when I attempt to access my method using a callback from the table component (Child), resulting in undefined behavior.

However, moving the pagination to the MasterGudang (Parent) Components seems to resolve the problem.

I'm struggling to comprehend what's causing this. The error message displays as "undefined" https://i.sstatic.net/SmOui.png

Below are snippets of code demonstrating the structure:

table.component.ts

import { Subject } from 'rxjs';

@Component({
  selector: 'ngx-table-custom',
  templateUrl: './table.component.html',
  styleUrls: ['./table.component.scss']
})
export class TableComponent implements OnInit {

  constructor() { }

  @Input() items: any;
  @Input() callback: any;
  @Input() columns: [];
  p: number = 1;

  @ContentChild('action', { static: false }) actionRef: TemplateRef<any>;
  ngOnInit(): void {
    this.items = new Subject();
    this.items.next();
  }

  onChangePage = (evt) => {
    this.callback()
  }

Gudang.component.ts

import { MasterGudangService } from '../../../../@core/services/master-service/menu-gudang/gudang/masterGudang.service';

@Component({
  selector: "ngx-gudang",
  templateUrl: './gudang.component.html',
  styleUrls: ['./gudang.component.scss'],
})

@Injectable({
  providedIn: 'root'
})
export class GudangComponent implements OnInit {

  constructor(
    public masterGudangService: MasterGudangService
    ) {
      console.log(masterGudangService)
    }

  tableData: [];
  isEdit: boolean = false;
  
  currentPage: number = 1;
  
  ngOnInit(): void {
    this.getList();
  }

  getList (page?: number) {
    this.masterGudangService.getPgb(page? page: this.currentPage).subscribe(response => {
      const { data: { content, totalElements, size, number } } = response;
      this.tableData = Object.assign({
        data: content,
        total: totalElements,
        size: size,
        number: number
      });
    });
  }
}

Here, I passed my function 'getList' to the table component:

gudang.component.html

 <ngx-table-custom [callback]="getList" [columns]="column" [items]="tableData">
      <ng-template let-item #action>
        <div class="row">
          <button nbButton status="success" (click)="open(dialog, item, true)" class="mx-2" size="tiny"gt;<nb-icon icon="edit"></nb-icon></button>
          <button nbButton status="danger" (click)="onDelete(item)" size="tiny"><nb-icon icon="trash"></nb-icon></button>
        </div>
      </ng-template>
    </ngx-table-custom>

MasterGudangService.ts

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class MasterGudangService {

  constructor(private http: HttpClient) { }

  getPgb (page: number = 1, perPage: number = 10) :any {
    return this.http.get(`my-api-url/pgb?page=${page}&size=${perPage}`)
  }
}

table.component.html

<div class="row">
  <div class="col-12">
    <table class="table table-md table-striped">
      <thead>
      <tr style="background-color: #3366ff; color: #fff;">
        <th *ngFor="let column of columns" class="text-basic">{{ column.value }}</th>
      </tr>
      </thead>
      <tbody>
      <tr *ngFor="let item of items.data | paginate: { itemsPerPage: 10, currentPage: p, totalItems: items.total }; index as idx;">
        <td *ngFor="let column of columns">
          <div *ngIf="column.key === 'number';"><b class="text-basic">{{ idx + 1 }}</b></div>
          <div *ngIf="column.key !== 'action' && !isNested(column.key);" class="text-basic">{{ item[column.key] }}</div>
          <div *ngIf="isNested(column.key);" class="text-basic">{{ getKeys(item, column.key) }}</div>
            <ng-template [ngIf]="column.key === 'action'" #action_content>
              <ng-container
              *ngIf="actionRef"
              [ngTemplateOutlet]="actionRef"
              [ngTemplateOutletContext]="{$implicit:item}">
            </ng-container>
          </ng-template>
        </td>
      </tr>
      </tbody>
    </table>
  </div>
</div>

<div class="row">
  <div class="col-12" align="center">
    <pagination-controls (pageChange)="onChangePage($event)"></pagination-controls>
  </div>
</div>


Answer №1

The Gudang.component.ts context will not be accessible through a callback from the table component.

It is recommended to pass the event instead of passing a function for the callback implementation.

table.component.ts

@Output() pageChange = new EventEmitter()
onChangePage = (evt) => {
   this.pageChange.emit(evt);
}

gudang.component.html

<ngx-table-custom (pageChange)="getList($event)" [columns]="column" [items]="tableData">
    ...
</ngx-table-custom>

Answer №2

It appears that the error is due to masterGudangService being null when you try to access it. To resolve this issue and gain insight into what's happening, consider adding the following code snippet:

ngOnInit(): void {
  if(this.masterGudangService)
    this.getList();
  else
    console.log('service not defined!');
}

Answer №3

To create a helper method in GudangComponent, you can do the following:

getHelperMethod() {
  return this.helperFunction.bind(this);
}

Then, simply utilize it like so:

<ngx-table-custom [callback]="getHelperMethod()" [columns]="column" [items]="tableData">

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Wind - Best practices for managing the status of multiple entities within a single display prior to executing the save changes function

In my system, there are three main entities: Project, Attachment, and Messages. A project can have multiple attachments and messages associated with it. The issue arises on the project detail view, where I display the project's messages and any attac ...

Material-UI organizes its Grid Items vertically, creating a column layout rather than a horizontal row

I'm struggling to create a grid with 3 items in each row, but my current grid layout only displays one item per row. Each grid item also contains an image. How can I modify the code to achieve a grid with 3 items in a row? Here's the code snippet ...

Model is updated by checkbox only on the second click

Take a look at this Plunkr example here: http://plnkr.co/edit/hwVL3xtnD9hGJL?p=preview After clicking the checkbox for the first time, the model fails to update. Can you explain why? var app = angular.module('main', ['ngMaterial']) ...

Disregard keys with null values when making a post request using react and axios

As a beginner in JavaScript, I am facing an issue where I do not want to include keys with null values when sending metadata. For example, I should only send the filepath as it has a value, and omit tags and owner which are null. How can I achieve this? ...

Transform leaflet marker plugin into Typescript format

I recently discovered a leaflet extension that conceals map markers if they fall outside the boundaries of the current view map. import L from 'leaflet'; L.Marker.MyMarker= L.Marker.extend({}).addInitHook(function (this: ILazyMarker) { this ...

What is the correct way to define functions within an object using Typescript in this situation?

Currently in the process of converting a JavaScript project to TypeScript, I encountered this error message (utilizing urql): A function whose declared type is neither 'void' nor 'any' must return a value. ts(2355) on line: playerCrea ...

"Modify the MySQL database each time a user changes the value in a

As a student, I am looking to update value(s) whenever a student changes the value(s) in the correction or update form. So far, I have been able to retrieve and display values in text boxes based on the name selected from a dropdown list from the database ...

Challenges with managing controllers within Directives

Currently, I am in the process of updating some code within a personal project that utilizes Angular to adhere to best practices. I have come across suggestions that the future direction of Angular involves incorporating a significant amount of functionali ...

The WebView.HitTestResult method is currently only receiving <img src> elements and not <a href> elements

I am attempting to open a new window in the Android browser using "_blank". I have set up an event listener for this purpose. mWebView.getSettings().setSupportMultipleWindows(true); mWebView.setWebChromeClient(new WebChromeClient() { ...

Is it not possible to make updates while the state is already in transition?

this.state = { filterData: [{ attribute: '-1', filter: '-1', value: '' }], } _createFilterUI(dataSourceColumns) { if (this.state.dataSourceIndex == -1) return <div > Kindly first select Data Sourc ...

After triggered window.print() in Angular, the window:afterprint event is failing to work as

I am triggering window.print() with a button click <button class="btn btn-primary" type="button" (click)="printDocument()"> Print </button> Inside the printDocument method, I open the document in a new window and ...

TypedScript: A comprehensive guide to safely omitting deep object paths

Hi there, I have a complex question that I would like some help with. I've created a recursive Omit type in TypeScript. It takes a type T and a tuple of strings (referred to as a 'path'), then removes the last item on the path and returns t ...

Enhancing Bootstrap Slider Range with jQuery/Javascript

Currently, I have incorporated the Bootstrap slider into a webpage that features two sliders on a single page. The range of the second slider depends on the value of the first one. It is crucial for me to be able to update the range of the second slider af ...

A method for transferring information stored in chrome.storage to a variable within an Angular component

How can I effectively assign data fetched from chrome.storage.sync.get to my Angular component's variable? Below is the code snippet of my component: export class KTableComponent implements OnInit { words: string[] = []; constructor() { } ...

Upon the second click, the addEventListener function is triggered

When using the window.addEventListener, I am encountering an issue where it only triggers on the second click. This is happening after I initially click on the li element to view the task information, and then click on the delete button which fires the eve ...

how can I display the JSON description based on the corresponding ID using Ionic 3

I have a JSON file containing: [{ "id": "1", "title": "Abba Father (1)", "description": "Abba Abba Father." }, { "id": "2", "title": "Abba Father, Let me be (2)", "description": "Abba Father, Let me be (2) we are the clay." }, { ...

Exploring the world of dynamic form creation using Angular and Mat-select options

I'm working on an Angular application and I want to create a dynamic form using Mat-select for the type selection. Depending on the chosen type, I need to be able to add or remove fields dynamically. I also want to display a specific field if the typ ...

Adjust the slide count accordingly when navigating to a particular item within the Bootstrap 3 Carousel

I made adjustments to the standard Bootstrap 3 Carousel so that it can navigate to a specific slide when the URL matches #. Although this feature is working, I am facing an issue with my pager-text not updating correctly when jumping to a specific slide. T ...

The issue with Angular routing lies in the component content not displaying as expected

To showcase my project, I've created a demo on StackBlitz. I successfully implemented routing in my Angular application. You can find the code on StackBlitz. The sample consists of two components: AppComponent LoginComponent By default, when the ...

Implement jQuery to close multiple div elements

My dilemma involves a series of divs with different manufacturer IDs listed as follows: manufacturer[1], manufacturer[2], manufacturer[3], ... etc ... In attempting to create a JavaScript for loop to hide each div, I discovered that it was not achievab ...