BennoDual
BennoDual

Reputation: 6259

how to use this in a callback-function?

I use a third-Party-Component for which I have to create an Object for configuration like itemMovementOptions in the following sample code.

export class AppComponent implements OnInit {
    readonly itemMovementOptions = {
      threshold: {
        horizontal: 25,
        vertical: 25,
      },
      events: {
        onMove({ items }) {
          for (let i = 0, len = items.after.length; i < len; i++) {
            const item = items.after[i];
            if (!this.canMove(item)) return items.before;
          }
          return items.after;
        },
      },
    };

    public canMove(item) {
       // ...
    }

    readonly config = {
        ItemResizing(this.itemResizeOptions),
        ItemMovement(this.itemMovementOptions),
    }

    ngOnInit(): void {
      GSTC.api.stateFromConfig(this.config);
    }
}

My Problem is now, that this is not pointing to AppComponent when the code will be executed so it could not find the method canMove().

Can someone help me, how I can solve this? I have to use canMove on several placed and do not want duplicate the code and putting it into the callback.

Upvotes: 0

Views: 1408

Answers (2)

Lesiak
Lesiak

Reputation: 25966

this binding is a source of confusion for new JS developers:

  • For regular functions it comes from the call context.
  • Arrow functions capture the this where the function is created rather than where it is invoked.

Observe:

class AppComponent  {
  onMoveFunction() {
    console.log("From onMoveFunction", this);
  }

  onMoveArrow = () => {
    console.log("From onMoveArrow", this);
  }
}

const c = new AppComponent();
const callbackFunction = c.onMoveFunction
const callbackArrow = c.onMoveArrow

c.onMoveFunction() // "From onMoveFunction",  AppComponent: {} 
c.onMoveArrow()    // "From onMoveArrow",  AppComponent: {} 
callbackFunction() // "From onMoveFunction",  undefined 
callbackArrow()    // "From onMoveArrow",  AppComponent: {} 

Another option is to use bind().

For more info:

Upvotes: 1

nate-kumar
nate-kumar

Reputation: 1771

There are two options here depending on the content of your canMove() function:

  1. If canMove() does not contain any references to this itself, that is, its logic is independent of the class/component that it is in, for example:

    app.component.ts

    canMove(item): boolean {
      return item.canMove;
    }
    

    then we can make the function static and reference it as follows:

    app.component.ts

    static canMove(item): boolean {
      return item.name;
    }
    
    ...
    if (!AppComponent.canMove(item)) return items.before;
    ...
    

    Note: This approach is also valid if the function is not in the component class, e.g.

    utilities.ts

    class Utilities {
      static canMove(item): boolean {
        return item.name;
      }
    }
    

    app.component.ts

    ...
    if (!Utilities.canMove(item)) return items.before;
    ...
    
  2. If canMove() does contain references to this, i.e. its logic is dependent on some content in the class/component that it is in, for example:

    app.component.ts

    canMove(item): boolean {
      return item.canMove && this.canMoveOverride;
    }
    

    we then need to provide the originating class context to the function when it is referenced so that when it is executed, all of the this. variables it needs to access (which are all defined in AppComponent) will be available. This is achieved using .bind() (docs)

    app.component.ts

    ...
    if (!this.canMove(item).bind(this)) return items.before;
    ...
    

Upvotes: 0

Related Questions