---
category: [Administration & Integrations, Platform and Product Extensions, Platform and Product Extensions/Integration, Administration & Integrations/Custom Integrations & Apps, Platform and Product Extensions/Workday Extend]
keyword: [Extend, PMD Scripting, Scripts]
nav: wcp_docs
parent_url: /wcp_docs/
title: >- 
  Reference: PMD Scripting Events
layout: subsection
---

<a id="section_wgq_5lq_rkb"></a>
The `self` variable is available to reference the widget or tag instance that fires the event. Specify the event as an attribute of the appropriate widget.

## <a id="section_onChange"></a>onChange

Triggers when the user changes the value of the widget.

The `onChange` event applies to these widgets on edit pages:

-   `checkBox`
-   `checkBoxList`
-   `currency`
-   `date`
-   `dropdown`
-   `instanceList`
-   `number`
-   `radioGroup`
-   `richText`
-   `text`
-   `textArea`
-   `time`


## <a id="section_onClick"></a>onClick

Triggers when the user clicks the `pageActionButton` widget on an edit page.

<b>Note:</b> The `onClick` event doesn't apply to the `button` widget.

## <a id="section_onFileAdd"></a>onFileAdd

Triggers when a file is successfully added or uploaded on the `fileUploader`. The `onFileAdd` event provides the `event.row` read-only property (and `getRow` method), which contains the row added to the `fileUploader` widget. Example:

```

"onFileAdd": "<%
  pageVariables.invalidFiles = pageVariables.invalidFiles ?? [];
  if (event.row.fileName.size() > 10) {
      pageVariables.invalidFiles.add(event.row.fileName);
  }
  if (! empty pageVariables.invalidFiles) {
      uploader.error = pageVariables.invalidFiles
          .map(fileName => `File {{fileName}} exceeded 10 characters.`)
          .join('\\n');
  }
%>"
 
```

## <a id="section_onFileRemove"></a>onFileRemove

Triggers when a file is successfully removed from the `fileUploader`. The `onFileRemove` event provides the `event.row` read-only property (and `getRow` method), which contains the row removed from the `fileUploader` widget. Example:

```

"onFileRemove": "<%
  pageVariables.invalidFiles.remove(event.row.fileName);
  if (! empty pageVariables.invalidFiles) {
      uploader.error = pageVariables.invalidFiles
          .map(fileName => `File {{fileName}} exceeded 10 characters.`)
          .join('\\n');
  }
  else {
      uploader.clearError()
  }
%>"
 
```

## <a id="section-on-load"></a>onLoad

Triggers after all inbound endpoints have finished fetching data and before loading any widget on the page. Specify the `onLoad` event as a root property of the PMD. Use the `onLoad` event handler to transform data to a desired format before the widgets consume the data.

The `onLoad` event fires only on initial load of the page. If an inbound endpoint uses the `pagingVariables.limit` and `pagingVariables.offset` for a paginated grid, the `onLoad` event handler can only perform data transformation for the initial grid rendering. The `onLoad` event handler doesn't execute again, and won't perform data transformation for the subsequent paged data.

<b>Notes</b>:

-   You can't reference any tag in the `onLoad` event handler. The page doesn't load any of the widgets until after the `onLoad` event has completed.
-   The `onLoad` event doesn't support the `invoke()` method on deferred inbound POST endpoints. To work around this limitation, you can open the page using a `button` with `commandHttpMethod` set to POST. You can then define a second endpoint as the deferred endpoint.


This sample `onLoad` event handler uses `pageVariables` to store a scorecard goal description and to filter scorecard names containing "<i>DO NOT USE</i>" from a list. The `text` and `instanceList` widgets display the stored values.

```
{
  "id": "onLoadView",
  "endPoints": [
    {
      "name": "allScorecards",
      "baseUrlType": "workday-compensation",
      "url": "/scorecards"
    },
    {
      "name": "aScorecard",
      "baseUrlType": "workday-compensation",
      "url": "<% '/scorecards/' + allScorecards.data[0].id %>",
    }
  ],
  "onLoad": "<%
        pageVariables.primaryGoal = aScorecard.defaultScorecardGoals[0].goalDescription;
        var scorecardGoals = [];
        for (var scorecard : allScorecards.data) {
            var currentScorecardName = scorecard.scorecardName;
            if (! currentScorecardName.contains('DO NOT USE') ) {
                  scorecardGoals.add({
                    'id': scorecard.id,
                    'descriptor': scorecard.scorecardName
                  })
            }
        }
        pageVariables.scorecardGoals = scorecardGoals;
    %>",
  "presentation": {
    "pageType": "edit",
    "body": {
      "type": "section",
      "children": [
        {
          "type": "text",
          "label": "Primary Scorecard",
          "enabled": "false",
          "value": "<% aScorecard.scorecardName + ' (effective: ' + aScorecard.effectiveDate + '):  ' + pageVariables.primaryGoal %>"
        },
        {
           "type": "instanceList",
           "label": "Use these scorecard goals:",
           "id": "scorecardGoalsList",
           "multiSelect": "true",
           "values": "<% pageVariables.scorecardGoals %>"
         }
      ]
    }
  }
}
```

## <a id="section_onMultiPartSend"></a>onMultiPartSend

Triggers just before sending data to a multipart outbound endpoint, enabling you to modify the JSON parts of a multipart request, such as file metadata. The `onMultiPartSend` event triggers when at least 1 widget specifies the `valueOutBinding` attribute with a form-data part. The `valueOutBinding` for a multipart endpoint uses either format:

-   `<outboundEndpointName>:<formDataName>` - The `valueOutBinding` format on a `fileUploader`.
-   `<outboundEndpointName>:<formDataName>:<jsonFieldName>` - The `valueOutBinding` format on any other widget.


The `onMultiPartSend` event applies only to `outboundEndPoints` that:

-   Are multipart endpoints.
-   Use the POST or PUT methods.


Use the `onMultiPartSend` event to manipulate and return `self.data`, which is a map containing the JSON parts of the multipart request. Each JSON part is a <<i>formDataName</i>, <i>Object</i>> pair where:

-   <i>formDataName</i> - The name that identifies the part. Specify the <i>formDataName</i> in the `valueOutBinding`. You can't use "`metadata`" as the <i>formDataName</i>.
-   <i>Object</i> - A map or array of JSON fields representing the data part.


<b>Notes</b>:

-   If the PMD script returns an empty or null `self.data`, only the uploaded files are sent to the outbound endpoint, which might fail without the data part.
-   If you're debugging an `onMultiPartSend` event handler with a `console` method, ensure that the `console` method isn't the last line of the script. The last line must be `self.data`.


See the `onMultiPartSend` examples in:

-   [Concept: fileUploader](/wcp_docs/ttn1652370891576.html)
-   [Concept: Submitting Data](/wcp_docs/rmd1572291186381.html)


## <a id="section_ycm_3yl_nrb"></a>onPanelAdd

Triggers when the user adds a panel to the `panelList`.

Example:

```
{
  "type": "panelList",
  "id": "myPanelList",
  "label": "Sample Panel List",
  "panels": "<% [] %>",
  "panelName": "item",
  "indexVariableName": "x",
  "children": [
    {
      "type": "text",
      "label": "<% 'Item ' + x  %>"
    }
  ],
  "onPanelAdd": "<% panelText.value = 'Panel added.' %>"
},
{
  "type": "text",
  "id": "panelText",
  "enabled": false
}
```

## <a id="section_q5x_4yl_nrb"></a>onPanelRemove

Triggers when the user removes a panel from the `panelList`.

Example:

```
{
  "type": "panelList",
  "id": "myPanelList",
  "label": "Sample Panel List",
  "panels": "<% [] %>",
  "panelName": "item",
  "indexVariableName": "x",
  "children": [
    {
      "type": "text",
      "label": "<% 'Item ' + x  %>"
    }
  ],
  "onPanelRemove": "<% panelText.value = 'Panel removed.' %>"
},
{
  "type": "text",
  "id": "panelText",
  "enabled": false
}
```

## <a id="section_onRowAdd"></a>onRowAdd

Triggers when the user adds a grid row on an edit page. Applies only to `grid` widgets that enable users to add grid rows. The `doNotAdd` attribute of the grid must be false (default).

This sample grid uses the `onRowAdd` and `onRowRemove` event handlers to update a number widget with the `quantityColumn` total.

```
{
  "type": "grid",
  "id": "requisitionGrid",
  "rows": "<% requisitions.data %>",
  "rowVariableName": "requisitionRow",
  "onRowAdd": "<% updateTotalQuantity() %>",
  "onRowRemove": "<% updateTotalQuantity() %>",
  "label": "Requisitions",
  "columns": [
     {
      "type": "column",
      "columnId": "reqDescriptor",
      "label": "Description",
      "cellTemplate": {
        "id": "reqDescriptorCell",
        "type": "text",
        "_comment": "Use the null-coalescing operator to set the default description if null (new row).",
        "value": "<% requisitionRow.descriptor ?? 'Default Description' %>"
      }
    },
    {
      "type": "column",
      "columnId": "quantityColumn",
      "label": "Quantity",
      "cellTemplate": {
        "id": "quantityCell",
        "type": "number",
        "value": "1"
      }
    }
  ]
}
```

This snippet displays the sample event handler `updateTotalQuantity`, which updates a sample `total` number widget:

```
var updateTotalQuantity = function () {
      total.value = requisitionGrid.getSubtotal('quantityColumn');
}
```

## <a id="section_onRowRemove"></a>onRowRemove

Triggers when the user removes a grid row on an edit page. Applies only to `grid` widgets that enable users to remove grid rows. The `doNotRemove` attribute of the grid must be false (default).

## <a id="section_onRowSelect"></a>onRowSelect

Triggers when the user selects or unselects a grid row. Applies only to `grid` widgets that enable users to select grid rows. The `selectionEnabled` attribute of the grid must be true. Also set the `maxRowSelection` attribute.

## <a id="section_onSearch"></a>onSearch

Triggers when the user enters a search string on the `instanceList` widget. The `onSearch`event handler must return a list of instances that contains the `id` and `descriptor` fields (or the fields configured in the `idKey` and `displayKey` attributes. You can use the `onSearch` event to:

-   Customize the list data based on page interactions.
-   Invoke deferred endpoints.
-   Run script logic for local search.
-   Replace the use of `searchEndPoint` and `searchValues`.

    <b>Note:</b> `onSearch`, `searchEndPoint`, and `searchValues` are mutually exclusive.



<b>event.query Property</b>

The `onSearch` event provides the `event.query` read-only property, which contains the search string that the user entered on the `instanceList` widget. See the "Populating a List with the onSearch Event" section in [Concept: instanceList](/wcp_docs/GUID-17f49183-14bb-4cd3-95a1-1e3dd8ded432-enHYPHENus.html).

## <a id="section_onSend"></a>onSend

Triggers just before sending the request data to an outbound endpoint or a POST inbound endpoint. Specify a PMD script that returns either a List or a Map, which is the request JSON data. The `onSend` event handler can reference all widget values on the page, including composite widgets such as `grid` rows or `panelList` panels.

Applies to these tags:

-   `outboundDataURI` in `outboundEndPoints` - The `onSend` event triggers just before the outbound endpoint invocation.
-   `outboundVariable` in `outboundEndPoints` - The `onSend` event triggers just before sending the data, typically to the next page in a flow.
-   A POST inbound endpoint in `endPoints` - The `onSend` event triggers just before the POST endpoint invocation.


<b>Notes:</b>

-   An `onSend` event handler that returns `null` prevents the invocation of a POST, PATCH, or PUT endpoint. However, the `null` return value still invokes a DELETE endpoint, which doesn't need a request payload.
-   If you're debugging an `onSend` event handler with a `console` method, ensure that the `console` method isn't the last line of the script. The last line of the `onSend` event handler must be `self.data`.
-   The `onSend` event doesn't support multipart outbound endpoints, such as endpoints that submit file attachments. For multipart outbound endpoints, use the `onMultiPartSend` event.
-   For outbound endpoints, `onSend` always executes, and `self.data` includes the data from the `values` attribute.


-   For outbound variables (both flow and session variables), the `values` attribute and `onSend` event are mutually exclusive. If you specify both, the `values` attribute takes precedence.



`onSend` usage:

-   Outbound data manipulation or special logic with `valueOutBinding`.

    The `valueOutBinding` attribute of a widget binds its value to the outbound data. If the PMD tags use the `valueOutBinding` attribute, you can use the `onSend` event handler to perform data manipulations just before sending the outbound data. You can also use the `onSend` event handler to perform any additional special logic on `self.data` before sending it.

    The `self.data` variable in an `onSend` event handler represents the outbound data, which includes data from all widgets that use the `valueOutBinding` attribute for the same outbound endpoint or variable. If the page widgets don't use any `valueOutBinding` for the outbound endpoint or variable, its `self.data` is null.

    This snippet uses a `text` with `valueOutBinding`, and an `outboundEndPoint` with `onSend`. The `onSend` script calls a sample function `getNewTitle()` to populate the `proposedBusinessTitle` before returning `self.data`. The `self.data` variable contains a JSON Map with the `proposedBusinessTitle` and `descriptor` fields.

    ```
    {
      "type": "text",
      "id": "currentBusinessTitle",
      "label": "Business Title",
      "value": "<% workerData.businessTitle %>",
      "valueOutBinding":"businessTitleChange.proposedBusinessTitle"
    },
    {
      "type": "text",
      "id": "name",
      "label": "Name",
      "value": "<% workerData.descriptor %>"
    },
    . . .
    "outboundData": {
        "outboundEndPoints": [
          {
            "name": "businessTitleChange",
            "baseUrlType": "workday-common",
            "url": "<% '/workers/' + queryParams.workerId + '/businessTitleChanges' %>",
            "httpMethod": "POST",
            "authType": "sso",
            "onSend": "<%
               self.data.proposedBusinessTitle = getNewTitle();
               self.data.descriptor = 'Title Change : ' + name.value;
               self.data;
            %>"
          }
        ]
    },
    ```

    Note that the sample `onSend` event handler includes the `descriptor` field to demonstrate that you can update any outbound JSON field in the event handler. The `POST workers/{id}/businessTitleChange` API ignores the `descriptor` field and automatically sets it.

-   Outbound data manipulation without `valueOutBinding`.

    You can use the `onSend` event handler to create the complete outbound JSON data. Instead of using `valueOutBinding` attributes from the page widgets, reference any of the page widget values to define the JSON data.

    This snippet uses a `text` tag without a `valueOutBinding`, and an `outboundEndPoint` with `onSend`. The `onSend` script returns a JSON Map containing the `proposedBusinessTitle` and `descriptor` fields. Their values reference the `text` widget values.

    ```
    {
      "type": "text",
      "id": "title",
      "label": "Business Title",
      "value": "<% workerData.businessTitle %>"
    },
    {
      "type": "text",
      "id": "name",
      "label": "Name",
      "value": "<% workerData.descriptor %>"
    },
    . . .
    "outboundData": {
        "outboundEndPoints": [
          {
            "name": "businessTitleChange",
            "baseUrlType": "workday-common",
            "url": "<% '/workers/' + queryParams.workerId + '/businessTitleChanges' %>",
            "httpMethod": "POST",
            "authType": "sso",
            "onSend": "<%
               {
                 'proposedBusinessTitle' : getNewTitle(),
                 'descriptor' : 'Title Change : ' + name.value
               };
            %>"
          }
        ]
    },
    ```

    Note that the sample `onSend` event handler includes the `descriptor` field to demonstrate that you can update any outbound JSON field in the event handler. The `POST workers/{id}/businessTitleChange` API ignores the `descriptor` field and automatically sets it.

-   Data retrieval or validation with a POST inbound endpoint.

    You can use the `onSend` event handler with a POST inbound endpoint that performs data retrieval or deferred validation.

    This sample deferred endpoint is a POST validation endpoint that uses the `onSend` event handler to send the phone number to validate:

    ```
    "endPoints": [
     {
       "name": "phoneValidation",
       "baseUrlType": "workday-person",
       "url": "/phoneValidation",
       "httpMethod": "POST",
       "deferred": true,
       "onSend": "<% { 'completePhoneNumber': thePhoneNumber.value } %>"
     }
    ]
    ```

    This sample `text` widget uses the `onChange` event handler to invoke the POST validation endpoint:

    ```
    {
      "type": "text",
      "label": "Phone Number",
      "id": "thePhoneNumber",
      "onChange": "<%
        var result = phoneValidation.invoke();
        if (! empty result.error) {
          self.setError(result.error);
        }
        else {
          self.clearError();
        }
     %>"
    }
    ```



## <a id="section-on-submit"></a>onSubmit

Triggers when the user clicks the <b>OK</b> button on an edit page. Specify the `onSubmit` event as a root property of the PMD.

Use the `onSubmit` event handler to perform page-level validations before calling any outbound endpoint on the page. If the event handler detects an error and calls the `setError` or `setWarning` method on any of the widgets, the page returns the message to the user. The page doesn't call any outbound endpoint.

<b>Note:</b> Use `onSubmit` for page-level validations. For field-level validations, use the `onChange` event on the widget.

This snippet validates widget values, and calls `setError` on a widget that requires the user to fix the error.

```
"onSubmit": "<%
        if (newBusinessTitle.value != '' && location.value == getValidLocation()) {
            location.clearError();
        }
        else {
            location.value = '';
            location.setError('Enter a valid location.');
        }
%>"
```

After the user sees the errors or warnings, the user must clear them before they can resubmit the page. If the user doesn't clear the error or warning:

-   The user can't resubmit the page.
-   The page can't trigger the `onSubmit` event again.


<b>event.ignoreWarnings() Method</b>

The `onSubmit` event provides the `event.ignoreWarnings()` method, which enables page submission to continue even if the page has encountered warnings.

To ignore warnings on the page and to allow users to continue with the page submission without clearing the warnings, call the `event.ignoreWarnings()` method. If you don’t call `event.ignoreWarnings()`, the user must resolve all the warnings before submitting the page.

<b>Note:</b> The `event.ignoreWarnings()` method only ignores page warnings. Page errors cannot be ignored.

The `onSubmit` event handler in this sample edit page ignores the warning when the user submits the page.

```
{
    "id": "editPageWithWarning",
    "presentation": {
        "pageType": "edit",
        "body": {
            "type": "section",
            "children": [
                {
                    "type": "text",
                    "id": "myText",
                    "onChange": "<% self.warning = 'Sample warning message.'; %>"
                }
            ]
        }
    },
    "onSubmit": "<%
        // Page submission is allowed when a warning is encountered.
        event.ignoreWarnings();
 
       // Custom onSubmit logic
       
    %>"
}
```

### Related Information

[Concept: PMD Scripting](/wcp_docs/oli1581402304020.html)

[Reference: PMD Scripting Syntax](/wcp_docs/snh1581402351791.html)

[PMD Scripting](/wcp_docs/jab1582081565510.html)

[Reference: PMD Scripting Examples](/wcp_docs/mdp1582058758619.html)

[App Catalog: PMD Scripting](/app-catalog/pmdScripting)

