Cannot read properties of this object values of parent component to child component function in angular

843 Views Asked by At

I'm calling a function declared in parent component in the child component in the form of callback.

Parent Component

translation-editor.component.ts

export class TranslationEditorComponent implements OnInit {
    textGuid: string = this.actRoute.snapshot.params['textGuid'];
    editDataset: any;
    currentTopBarConfig: any;
    summaryTopbarConfig = [
      {
        "label": "Save Text",
        "function": this.save,    //see save function below
      },
      { 
        "label": "Delete Text", 
        "function": this.delete, 
      }
    ];
  constructor(
    private translationService:TranslationService,
    public actRoute: ActivatedRoute,
  ) {
  }

  ngOnInit(): void {
    this.loadDataToEdit();
  }
  loadDataToEdit(){
    this.translationService.getTextById(this.textGuid).subscribe(res => {
      this.editDataset = res;
    })
    this.currentTopBarConfig = this.summaryTopbarConfig;
  }
  save(){
    console.log("this.textGuid",this.textGuid);
    if(this.textGuid){
      this.translationService.updateText(this.textGuid, this.editDataset).subscribe((res:any)=>{
        console.log(res);
      });
    }
  }
  delete(){
 console.log("delete code lies here");
  }
}

translation-editor.component.html

<topbar [config]="currentTopBarConfig"></topbar>

<form  [ngClass]="{'hidden':currentTab!=='summary'}" >
    <fieldset>
      <legend>Field</legend>
      <ul  *ngIf="editDataset">
        <ng-container  *ngFor="let key of objectKeys(editDataset)" >
          <li *ngIf="key === 'textGuid' || key === 'strongName' || key === 'container'">
            <label class="grid-input-group">
              <input type="text" value="{{editDataset[key]}}" readonly>
              <span class="label">{{key}}</span>
            </label>
          </li>
        </ng-container>

      </ul>
    </fieldset>

  </form>

I'm calling the save function in the below component as a callback to initiateFunction() function.

Child Component

topbar.component.html

<ul class="sidebar-items">
<ng-container *ngFor="let btn of config">
  <li>
    <button 
      (click)="initiateFunction(btn.function)"
      <span class="label" >{{btn.label}}</span>
    </button>
  </li>
</ng-container>
</ul>

topbar.component.ts

export class TopbarComponent implements OnInit {
    @Input() config: any[] | undefined;
    constructor(private location: Location) { }
    ngOnInit(): void {
    }
    initiateFunction(fnct:any){
      fnct();
    }
  }

Here when function is executed I'm getting an error:

ERROR TypeError: Cannot read properties of undefined (reading 'textGuid')

Where I'm not able access the this.textGuid.

Please give me suggestions on how to solve this.

2

There are 2 best solutions below

0
On BEST ANSWER

I think the issue is caused because the save() function isn't bound to the correct object, so instead you can use Angular component interaction features. You can use @Output decorator and emit an event that will be handled by parent component.

First, update your TopbarComponent to add that event:

topbar.component.ts

export class TopbarComponent implements OnInit {
  @Input() config: any[] | undefined;
  @Output() save: EventEmitter<any> = new EventEmitter();
  
  constructor(private location: Location) {}
  
  ngOnInit(): void {}
  onSave() {
    this.save.emit();
    //fnct();
  }
}

topbar.component.html there was a typo on in button start tag >

<ul class="sidebar-items">
<ng-container *ngFor="let btn of config">
  <li>
    <button 
      (click)="onSave()">
      <span class="label" >{{btn.label}}</span>
    </button>
  </li>
</ng-container>
</ul>

Next, update the TranslationEditorComponent component to bind to that event: translation-editor.component.html

<topbar [config]="currentTopBarConfig" (save)="save()"></topbar>

You can do the same for other types of events like delete or update. Refer to Angular docs for more details about components interaction and sharing data https://angular.io/guide/inputs-outputs

1
On

Your this context has been changed when you call fnct();. In order to pass the this context to the function you can use javascript bind method. So you just need to change the config property:

summaryTopbarConfig = [
      {
        "label": "Save Text",
        "function": this.save.bind(this),    //bind current context
      }
    ];

Read more about bind: https://www.w3schools.com/js/js_function_bind.asp