Edit

Share via


Tutorial: Define a custom event in a component

[This topic is pre-release documentation and is subject to change.]

In this tutorial, you'll build a code component that uses custom events and test it using both canvas and model-driven apps. Learn more about the custom events preview.

Goal

The steps in this tutorial guide you to create a code component with two buttons which raise different events for the hosting application can react to. You'll define two events: customEvent1 and customEvent2. Then, the code component exposes two buttons that cause these events to occur.

Canvas App

The canvas app uses Power Fx expressions on these events to toggle the visible and display mode properties of a control:

Diagram shows the goal of this sample to define two custom events

Model-driven App

The model-driven app uses client-side JavaScript to show an alert when the respective events occur.

Prerequisites

You should already know how to:

Create a new Control

  1. Create a new component using this command:

    pac pcf init -n EventSample -ns SampleNamespace -t field -fw react -npm

  2. Edit the manifest to add the new events

<property name="sampleProperty"
   display-name-key="Property_Display_Key"
   description-key="Property_Desc_Key"
   of-type="SingleLine.Text"
   usage="bound"
   required="true" />
<resources>
   <code path="index.ts"
      order="1"/>
   <platform-library name="React"
      version="16.8.6" />
   <platform-library name="Fluent"
      version="8.29.0" />
   <css path="css/SampleEventPCF.css" order="1" />
   <resx path="strings/SampleEventPCF.1033.resx" version="1.0.0" />
</resources>

Define events

In the EventSample\HelloWorld.tsx control file, define two events in the interface and bind the events to two different buttons. Also update the import to include DefaultButton as the following changes show.

import * as React from 'react';
import { Label } from '@fluentui/react';

export interface IHelloWorldProps {
  name?: string;
}

export class HelloWorld extends React.Component<IHelloWorldProps> {
  public render(): React.ReactNode {
    return (
      <Label>
        {this.props.name}
      </Label>
    )
  }
}

Modify updateview method

In EventSample\Index.ts, modify the updateView method to add handlers for the two button events. These handlers add the two events defined in the manifest to the events in the context passed to the control.

public updateView(context: ComponentFramework.Context<IInputs>): React.ReactElement {
   const props: IHelloWorldProps = { name: 'Hello, World!' };
   return React.createElement(
      HelloWorld, props
   );
}

Build and package

As usual, you need to complete these steps to use this control:

  1. Create and build the code component
  2. Package the code component
  3. Deploy the code component

Use in a canvas app

To use this control in a canvas app, you need to:

  1. Create a new blank Canvas App

  2. Add the new component to the canvas app

  3. Add a new control. This example uses a text control.

    Image of the Canvas App with controls added.

  4. Add two global variables to the app: isVisible and canEdit.

  5. Set canEdit to the DisplayMode property of the text control.

    Image of the DisplayMode property of the text control

  6. Set isVisible to the Visible property of the text control.

    Image of the Visible property of the text control

  7. Set custom actions on the new custom control to update the isVisible and canEdit variables when the buttons are clicked.

    Image of the Custom Event properties of the new component

    Event Power FX expression
    customEvent1 If(isVisible, Set (isVisible, false), Set (isVisible, true))
    customEvent2 If(canEdit = DisplayMode.Edit, Set(canEdit, DisplayMode.Disabled), Set (canEdit, DisplayMode.Edit))

Test the canvas app

  1. Press Trigger event 1.

    Expected: The text control toggles between visible and hidden

  2. Press Trigger event 2.

    Expected: The text control toggles between editable and read only.

Use in a model-driven app

Note

These steps refer to instructions described in Walkthrough: Write your first client script.

  1. Create a new JavaScript web resource to run on the onLoad event of a form. This script binds two event handlers to the new events for the controls on load of the form.

    /* eslint-disable */
    "use strict";
    
    var MyScriptsNameSpace = window.MyScriptsNameSpace || {};
    (function () {
    
    const controlName1 = "cr116_personid";
    
    this.onLoad = function (executionContext) {
       const formContext = executionContext.getFormContext();
    
       const sampleControl1 = formContext.getControl(controlName1);
       sampleControl1.addEventHandler("customEvent1", this.onSampleControl1CustomEvent1);
       sampleControl1.addEventHandler("customEvent2", this.onSampleControl1CustomEvent2);
    };
    
    this.onSampleControl1CustomEvent1 = function (params) {
       alert(`SampleControl1 Custom Event 1`);
    }.bind(this);
    
    this.onSampleControl1CustomEvent2 = function (params) {
       alert(`SampleControl1 Custom Event 2`);
    }.bind(this);
    
    }).call(MyScriptsNameSpace);
    
  2. Complete the following steps as you normally do:

    1. Upload your new JavaScript file as a web resource.
    2. Add the component to the model-driven form.
    3. Associate the webresource to the form.
  3. Configure the On Load event as shown in the following image:

    Image of the JavaScript binding for the Model Driven App Form

  4. Test your app.

    When you navigate to the form and press Trigger event 1, an alert displays SampleControl1 Custom Event 1. When you press Trigger event 2, an alert displays SampleControl1 Custom Event 2.

Passing payload in events

As described in Defining an event for model-driven apps, you can pass payload in events in model-driven apps. You can modify this example in the following way to see how this works.

Diagram shows multiple controls generating multiple events with a call back being made

Pass payload with event

Change the EventSample\index.ts so that the events pass a message payload and in the second event also pass a callback function that changes an internal variable

public updateView(context: ComponentFramework.Context<IInputs>): React.ReactElement {
   const props: IHelloWorldProps = {
      onCustomEvent1: ()=> {
            context.events.customEvent1()
      },
      onCustomEvent2: () => {
            context.events.customEvent2()
      }
   };
   return React.createElement(
      HelloWorld, props
   );
}

Then:

  1. Rebuild and Deploy the component.

  2. Add another field to the form used before and also set that to use the new component.

    Diagram shows multiple controls added to the form

Use the payload in the event handler

Update the onLoad function to set the event handlers on the custom controls to react to events from both controls and also to make use of the parameters being passed

/* eslint-disable */
"use strict";

var MyScriptsNameSpace = window.MyScriptsNameSpace || {};
(function () {

const controlName1 = "cr116_personid";

this.onLoad = function (executionContext) {
   const formContext = executionContext.getFormContext();

   const sampleControl1 = formContext.getControl(controlName1);
   sampleControl1.addEventHandler("customEvent1", this.onSampleControl1CustomEvent1);
   sampleControl1.addEventHandler("customEvent2", this.onSampleControl1CustomEvent2);
};

this.onSampleControl1CustomEvent1 = function (params) {
   alert(`SampleControl1 Custom Event 1`);
}.bind(this);

this.onSampleControl1CustomEvent2 = function (params) {
   alert(`SampleControl1 Custom Event 2`);
}.bind(this);

}).call(MyScriptsNameSpace);

Test the model-driven app

  1. Navigate to the form.

  2. Press Trigger event 1 on the first field.

    Expected: A pop-up displays SampleControl1 Custom Event 1: Hello from event 1 on the first field.

  3. Press Trigger event 2 on the first field.

    Expected: A pop-up displays SampleControl1 Custom Event 2: Hello from event 2 on the first field followed by an alert from the first control that says Event 2 default NOT prevented

  4. Press Trigger event 1 on the second field.

    Expected: A pop-up displays SampleControl2 Custom Event 1: Hello from event 1 on the second field.

  5. Press Trigger event 2 on the second field.

    Expected: A pop-up displays SampleControl2 Custom Event 2: Hello from event 2 on the second field followed by an alert from the second control that says Event 2 default prevented

Define Events (preview)