1
votes

I am passing a function from my parent component, to my child component's Input() property.

The problem is, the parent's function is invoked in the child component, and the this keyword, now refers to the child component's context, instead of the parent components context.

Here is an example of what I am doing in my parent component:

export class CustomerComponent implements OnInit {
    next(continuationToken: string): Observable<CustomerSearchResult> {
        console.log('invoked');
        return this.customerService.searchCustomersPaged("andrew");
    }
}

In my parent component's template (I am passing the 'next' function through the input parameter named 'nextDelegate'):

<app-datatable [hidden]="!customersByFirstNameHasResults" [nextDelegate]="next" [serverSidePaging]="true" id="customersByFirstName" [showDeleteButton]="false" [showEditButton]="true" [responseModelObservable]="customersByFirstName"
      modelTypeName="customer" (editRow)="editCustomer($event)">
    </app-datatable>

And then finally, in my child component, I try and invoke the method passed in, but the context is wrong.

export class DatatableComponent implements AfterViewInit, OnDestroy, OnInit {
  @Input() nextDelegate: (continuationToken: string) => Observable<CustomerSearchResult>;

private initializeDtOptions() {
// storing current class reference in a variable to use it in jQuery 

// function because we can't 
    //use arrow function as we might need both this' in the function
    if (this.serverSidePaging) {
      this.dtOptions = {
        pagingType: 'simple',
        serverSide: true,
        processing: true,
        pageLength: 10,
        deferLoading: 100, //this.totalRecords
        ajax: (p, callback) => {
          //called here
          that.nextDelegate("").subscribe(x => {
            callback({

            })
          });

        }
      };
    } else {
      this.dtOptions = {
        pagingType: 'full_numbers',
        columns: this.columnSettings
      };
    }
  }
}
1
What exactly are you trying to achieve here? I seriously think passing a function as an @Input is an anti-pattern. You could create an @Output property on your child component, and emit from there passing all the relevant data and have your function in your Parent Component that you wanted to call, behave as a handler to that event instead. - SiddAjmera
While it sounds like maybe structurally you're doing things in a way that goes against the Angular design pattern, what you're experiencing here is scope issues. MPJ has an excellent video tutorial on how .bind 'can re-point where .this' refers to. You'll find it at youtube.com/watch?v=GhbhD1HR5vk - Bytech

1 Answers

1
votes

by context I think you mean scope. This is wrong because of how your function is defined.

Try using:

export class CustomerComponent implements OnInit {
    public next = (continuationToken: string): Observable<CustomerSearchResult> => {
        console.log('invoked');
        return this.customerService.searchCustomersPaged("andrew");
    }
}

That said, this does seem to be a bit smelly. I would suggest using outputs, or injecting a service to handle this.