Question

I am new to TypeScript and SPFx development.

I have a jquery UI dialog box and a public function in the same class that makes some MSGRAPH calls after the button has been clicked.

The button click returns with error:

this.addAlert is not a function

I think the problem is that the dialog code executes outside the web part context and hence does not know about the function available in the webpart context.

How can I use the button click to run within the webpart context?

Here is the Dialog code.

    public render(): void {

    this.domElement.innerHTML = AlertTemplate.templateHtml;
    const dialogOptions: JQueryUI.DialogOptions = {
      width: "50%",
      height: "auto",
      buttons: {
        "Subscribe": function (e) {
          this.addAlert("Yes");
          jQuery(this).dialog("close");
        },
        "No Thanks": function (e) {
          console.log("moo");
          this.addAlert("No");
          jQuery(this).dialog("close");
        },
        "Ask me later": function (e) {
          this.addAlert("Ask Me Later");
          jQuery(this).dialog("close");
        }
      }
    };

    jQuery('.dialog', this.domElement).dialog(dialogOptions);
    jQuery(".ui-dialog-titlebar").hide();
  }

function addAlert

public addAlert(status: string): void {
var url = "/sites/" + this.context.pageContext.site.id + "/lists";
var listId = "";
var email = this.getCurrentUserEmail();
var recordExists = false;
let item: SubscriptionListItem;
this.context.msGraphClientFactory
  .getClient()
  .then((client: MSGraphClient): void => {
    client
      .api(url)
      .top(1)
      .filter("equals=(displayName, 'Subscriptions'")
      .version("v1.0")
      .get((err, res) => {
        if (err) {
          console.error(err);
          return;
        }
        console.log(res);
        listId = res.id;
      });
  });
Was it helpful?

Solution

The this reference inside the context of the event handler is not a reference to your react component. this in that context is usually the object that triggered the event, such as the clicked button. In JSX you can use binding to bind your event handler to the context of your component:

You have to be careful about the meaning of this in JSX callbacks. In JavaScript, class methods are not bound by default. If you forget to bind this.handleClick and pass it to onClick, this will be undefined when the function is actually called.

This is not React-specific behavior; it is a part of how functions work in JavaScript. Generally, if you refer to a method without () after it, such as onClick={this.handleClick}, you should bind that method.

There are multiple techniques in the above referenced article for binding your event handlers to your component's this context, but here is one example:

public onDialogButtonClick(status: string, e): void {
    this.addAlert(status);
    jQuery('.dialog', this.domElement).dialog("close");
}

public render(): void {
    this.domElement.innerHTML = AlertTemplate.templateHtml;
    const dialogOptions: JQueryUI.DialogOptions = {
      width: "50%",
      height: "auto",
      buttons: {
        "Subscribe": this.onDialogButtonClick.bind(this, "Subscribe"),
        "No Thanks": this.onDialogButtonClick.bind(this, "No Thanks"),
        "Ask me later": this.onDialogButtonClick.bind(this, "Ask me later")
      }
    };

    jQuery('.dialog', this.domElement).dialog(dialogOptions);
    jQuery(".ui-dialog-titlebar").hide();
}
Licensed under: CC-BY-SA with attribution
Not affiliated with sharepoint.stackexchange
scroll top