Custom Events in PCF Components
Introduction
In modern low-code development, Power Apps Component
Framework (PCF) plays a vital role in enhancing the user interface and
delivering rich interactive components. As part of building truly dynamic PCF
components, one powerful capability is the event mechanism—especially custom
events that allow developers to trigger and listen to component-specific
behavior across the app.
In this post, we'll explore how PCF components handle
events, including how to raise and handle custom events. We’ll also look at
practical use cases, implementation steps.
What Are Events in PCF?
Events in PCF enable components to communicate with the model-driven
app form or other consumers of the control. Microsoft introduced support for custom
event handling, allowing PCF control to:
- Raise
events from within the control (e.g., on button click).
- Notify
the hosting form or script when something changes in the control.
- Enable
loosely coupled communication between PCF and form JavaScript.
This makes your components not just reusable—but also
responsive and context-aware.
Types of Events
In PCF, you can deal with:
- Standard
events – such as notifyOutputChanged() to let the platform know output
properties have changed.
- Custom
events – defined and raised by the developer for more granular
control.
We’ll focus on custom events here.
Why Use Custom Events in PCF?
Some real-world scenarios where custom events make sense:
- A
multi-select dropdown PCF control where you want to fire a form-level
alert when a specific value is chosen.
- A file uploader control where form logic should be triggered after file validation succeeds.
What We’ll Build
The steps will 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.
Prerequisites
Before starting, ensure you have:
- Power
Apps CLI installed
- Node.js
and NPM.
- A
Dataverse environment.
- Visual Studio Code.
Create a new control:
1.
Create a new component using similar command. –
pac pcf init -ns Mahesh -n CustomEventForPCF -t field -fw react -npm
2.
Edit the Manifest file to add the new events
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><manifest><control namespace="Mahesh" constructor="CustomEventForPCF" version="0.0.2" display-name-key="CustomEventForPCF" description-key="CustomEventForPCF description" control-type="virtual" api-version="1.3.18"><property name="sampleProperty" display-name-key="Button Label" description-key="Enter a label for button" of-type="SingleLine.Text" usage="bound" required="true"/><event name="customEvent1" display-name-key="customEvent1" description-key="customEvent1"/><event name="customEvent2" display-name-key="customEvent2" description-key="customEvent2"/><resources><code path="bundle.js" order="1"/><platform-library name="React" version="16.14.0"/><platform-library name="Fluent" version="9.46.2"/></resources><feature-usage/><built-by name="pac" version="1.46.1"/></control></manifest>
Define events:
Rename the HelloWorld.tsx file and define two events in the
interface and bind the events to two different buttons. Also update the import
to include DefaultButton as below.
import * as React from 'react';import { Label, DefaultButton } from '@fluentui/react';export interface IButtonProps {onCustomEvent1: () => void;onCustomEvent2: () => void;}export class Button extends React.Component<IButtonProps> {public render(): React.ReactNode {return (<><Label>PCF Control with Event</Label><DefaultButton onClick={this.props.onCustomEvent1}>Trigger event 1</DefaultButton><DefaultButton onClick={this.props.onCustomEvent2}>Trigger event 2</DefaultButton></>)}}
Modify updateView method:
In 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.
import { IInputs, IOutputs } from "./generated/ManifestTypes";import { Button, IButtonProps } from "./Buttons";import * as React from "react";export class CustomEventForPCF implements ComponentFramework.ReactControl<IInputs, IOutputs> {private notifyOutputChanged: () => void;/*** Empty constructor.*/constructor() {// Empty}/*** Used to initialize the control instance. Controls can kick off remote server calls and other initialization actions here.* Data-set values are not initialized here, use updateView.* @param context The entire property bag available to control via Context Object; It contains values as set up by the customizer mapped to property names defined in the manifest, as well as utility functions.* @param notifyOutputChanged A callback method to alert the framework that the control has new outputs ready to be retrieved asynchronously.* @param state A piece of data that persists in one session for a single user. Can be set at any point in a controls life cycle by calling 'setControlState' in the Mode interface.*/public init(context: ComponentFramework.Context<IInputs>,notifyOutputChanged: () => void,state: ComponentFramework.Dictionary): void {this.notifyOutputChanged = notifyOutputChanged;}/*** Called when any value in the property bag has changed. This includes field values, data-sets, global values such as container height and width, offline status, control metadata values such as label, visible, etc.* @param context The entire property bag available to control via Context Object; It contains values as set up by the customizer mapped to names defined in the manifest, as well as utility functions* @returns ReactElement root react element for the control*/public updateView(context: ComponentFramework.Context<IInputs>): React.ReactElement {const props: IButtonProps = {onCustomEvent1: ()=> {context.events?.customEvent1()}, onCustomEvent2: () => {context.events?.customEvent2()}};return React.createElement(Button, props);}/*** It is called by the framework prior to a control receiving new data.* @returns an object based on nomenclature defined in manifest, expecting object[s] for property marked as "bound" or "output"*/public getOutputs(): IOutputs {return { };}/*** Called when the control is to be removed from the DOM tree. Controls should use this call for cleanup.* i.e. cancelling any pending remote calls, removing listeners, etc.*/public destroy(): void {// Add code to cleanup control if necessary}}
Build and package
As usual, you need to complete these steps to use this
control:
Use in a Model-Driven app:
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.
var Mahesh = Mahesh || {};Mahesh.ContactForm={onLoad: function(exeContext){Mahesh.ContactForm.addEventHandlerOnPCFCustomEvent(exeContext);},addEventHandlerOnPCFCustomEvent : function(exeContext){const formContext = exeContext.getFormContext();const sampleControl1 = formContext.getControl("new_pcffield");sampleControl1.addEventHandler("customEvent1", Mahesh.ContactForm.onSampleControl1CustomEvent1);sampleControl1.addEventHandler("customEvent2", Mahesh.ContactForm.onSampleControl1CustomEvent2);},onSampleControl1CustomEvent1: function(exeContext){alert(`SampleControl1 Custom Event 1`);},onSampleControl1CustomEvent2: function(exeContext){alert(`SampleControl1 Custom Event 2`);}}
2.
Configure the onload event as shown in the
following image:
3. 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.
Similarly, you can also pass Payload along with the Custom Event: Tutorial:
Define a custom event in a component - Power Apps | Microsoft Learn
You will also be able to call these Custom Events in Canvas
apps: Tutorial:
Define a custom event in a component - Power Apps | Microsoft Learn
Define Events (preview) - Power Apps | Microsoft Learn
Tutorial: Define a custom event in a component - Power Apps | Microsoft Learn
Comments
Post a Comment