7 Adding Functionality with Plug-ins#

When native APEX features don't fully meet your needs, you can easily extend the platform with plug-ins. These shared components add new functionality to your apps like a new kind of region, page item, dynamic action, page process, AI tool, workflow activity, data source, or scheme for authentication or authorization.

Developers with basic web design skills can create template components with no code, while other plug-in types require coding skills. Once a plug-in exists, the rest of the team can use it declaratively just like a built-in feature. However, before creating one yourself, search the APEX community "app store" site https://apex.world. The extended functionality you need might already be just a download away.

When your application incorporates plug-ins, you can review where each is used on the Utilization tab of the Shared Components > Plug-ins list page.

7.1 Reusable Components Using HTML Skills#

A template component is a reusable user interface element you create without coding.

Developers familiar with basic HTML, placeholder #NAME# substitution, and HTML directives can create sophisticated, reusable user interface controls. Other team members use template components just like native ones in Page Designer, configuring their settings in the Property Editor.

7.2 Using a Plug-in from apex.world#

By using a existing plug-in from the apex.world "app store", you can quickly add new functionality that another developer or team has made available to the APEX community.

The apex.world site is accessible at https://apex.world

7.1.1 Template Component Overview#

You can create a reusable UI component using templates with HTML tags, #NAME# placeholder substitutions, and template directives for conditional formatting.

Custom attributes let teammates use Page Designer to configure the data your component displays and the settings that influence its output. Your component can include slots developers see in Page Designer as areas where they can add other components of the kinds you allow.

Developers can apply your component using the {with/}…{apply/} directive, and optionally use it in Page Designer:
  • as a custom region that can contain other components,
  • to format a single row of data, or
  • to render multiple rows.

When used as a multi-row report, it can automatically support grouping, row selection, and pagination as well. If your component uses Cascading Style Sheets (CSS) rules or JavaScript, you can include those files as part of the component's definition.

Imagine creating a simple template component to display NAME and VALUE attributes using a template like:

<strong>#NAME#</strong> → #VALUE#

The figure below shows a page that uses this component in the body of a Cards region and in the column of a classic report to display employee names and salaries. It also uses the component as a single-row partial to display employee KING's job and salary.

Figure 7-1 Reusing a Template Component Three Different Ways

7.1.2 Custom Attributes for Data and Settings#

The custom attributes you define are named placeholders developers configure in the Property Editor to provide the data the component displays and any settings it requires.

Your templates use directives referencing custom attribute names to conditionally format data as required and #ATTRNAME# syntax to include an attribute's value.

In addition to a static ID and name, each attribute definition has other details that inform the Property Editor experience in Page Designer. For example, attributes of type Session State Value show developers a select list to choose a data source column name. A Yes/No type attribute displays an on/off switch, and a Select List lets developers choose a pre-defined option from a set you specify. Use other attribute types to show an icon picker, a color picker, an HTML code editor, a link builder, and more. You can define help text and examples for each attribute that a developer can consult in the Help tab in Page Designer to better understand how each setting affects the component's output.

As shown below, by default, your custom attributes display in the Property Editor's Attributes tab in the general Settings section in the display sequence you configure. If multiple attributes contribute to a common purpose, create an attribute group and assign related attributes to that group. The Property Editor displays the grouped attributes in a titled section to clarify how multiple properties affect one aspect of a component's features.

Figure 7-2 Custom Attributes in the Settings Section

7.1.3 Slots Enable Component Composition#

It's easy to define a component that can compose other regions, page items, and buttons. Just define a named slot and include its contents in your template using the #SLOTNAME# syntax.

Page Designer helps developers add the buttons, page items, or regions you allow into these slots and enforces any constraints on the slot contents that you configure. In short, if you say a particular slot can only contain buttons, then Page Designer makes sure teammates follow your rules.

For example, consider a template component named Content with Action Buttons with two slots named MAIN_CONTENT and ACTION_BUTTONS. Its simple partial template can use {if/} directives to conditionally format the contents of these two slots as follows. Notice the formatting of the MAIN_CONTENT slot changes depending on whether the developer has provided a value for the HEIGHT custom attribute.

{if ACTION_BUTTONS/}
  <div class="action-buttons">
    #ACTION_BUTTONS#
  </div>
{endif/}
{if HEIGHT/}
  <div style="height:#HEIGHT#">
    #MAIN_CONTENT#
  </div>
{else/}
  #MAIN_CONTENT#
{endif/}

When defining the slots, you can indicate, as shown below, that the ACTION_BUTTONS slot should only allow buttons and that the MAIN_CONTENT slot should only allow regions and support the 12-column grid layout. In the Default Slots section below, notice that you can indicate that the Main Content slot is the default slot for subregions and that Action Buttons is the default slot for buttons. These additional details further simplify the Page Designer experience for developers using the component.

Figure 7-3 Configuring Slot Behavior in a Template Component

When a developer uses the Content with Action Buttons component on a page, as shown below, Page Designer displays the Action Buttons slot and ensures they can only add buttons into it. Similarly, the developer can only add regions into the Main Content slot.

Figure 7-4 Using a Template Component's Slots in Page Designer

Running the page, you see below how the Content with Action Buttons component styles the buttons contained in the ACTION_BUTTONS slot and contains two regions each using 6 columns of the 12-column grid row in the MAIN_CONTENT slot.

Figure 7-5 Template Component Positions and Styles Composed Buttons and Regions

In another page, you can use the Content with Action Buttons component with different buttons and regions to create a tabbed display of department information. The figure below shows Adjust Budget and Initiate Audit buttons in the Action Buttons component slot, and in the Main Content slot, Department Info and Budget History tabs appear with their respective contents.

Figure 7-6 Different Usage of Content with Action Buttons Template Component

7.1.4 Applying Template Using Directives#

Developers can use a template component with internal name TEMPLATE_NAME anywhere directives are allowed.

The developer supplies any necessary attribute values and applies the template using the syntax:

{with/}
   ATTR1:=VALUE1
   ATTR2:=VALUE2
    ⋮
{apply TEMPLATE_NAME/}

7.1.5 Controlling Component Availability#

Using the {with/}…{apply/} directive, developers can always apply your template component by name, but you decide if they can use it in Page Designer by setting its Available as options.

If you select any of these options, Page Designer displays your component in the region palette and the list of region types. The particular option you choose controls how the Property Editor presents the component's features.

A Region-only component displays your custom attributes and slots, but offers no additional built-in settings. Choosing Single (Partial) or Multiple (Report) causes the Property Editor to show the Source section so a developer can configure a data source. Its columns are then available to reference in custom attributes. The data source for a Single (Partial) template component must return at most one row, or a runtime error results. Given this guarantee, the component renders only its Partial template with no additional space used for pagination controls.

When you make your template component available as a Multiple (Report) component, additional settings related to pagination and grouping appear. If you checked Has Row Selection Support when defining it, further settings appear for this capability.

7.1.6 Templates Comprising the Component#

A template component always has a primary template called the Partial. This name evokes the role it plays as a part of the web page at runtime. Your Partial template includes the main markup that determines how the component's attributes appear on the page.

If you make your component available as a Multiple (Report) type region, then you can define additional templates:

  • Report Row wraps each row of data and includes the partial with #APEX$PARTIAL#
  • Report Group wraps each distinct group of rows and includes them with #APEX$ROWS#
  • Report Body wraps the current page of rows and includes them with #APEX$ROWS#
  • Report Container wraps the report body and includes it with #APEX$REPORT_BODY#

Consider a template component Grouped Name/Value Pairs that defines a report attribute TITLE, component attributes NAME and VALUE, group attributes named GROUPNAME and GROUPID, as well as a BUTTONS slot. The figure below shows how the different templates cooperate to produce the result on the right. The developer has configured the title, chosen DNAME and DEPTNO for the group name and id, used ENAME and SAL for the name and value attributes, and added a single (Process Selected Employees) button into the Buttons slot.

Figure 7-7 Templates Involved to Format a Multiple (Report) Component

7.1.7 Presenting Grouped Data#

When you make your template component available as a Multiple (Report) region, it can present the rows from its data source grouped by common values. Define the HTML markup that should appear for each distinct group using the Report Group template that includes the rows in the group using #APEX$ROWS#.

When using the template component, configure the data source and enable the Group switch on one or more columns based on whose values you want the component to group its rows. All columns for which you enable the Group switch must appear in the region data source's ORDER BY clause. Your component will format a new group for each distinct combination of the grouping columns.

Once at least one column has the Group switch enabled, as shown below, additional Report Group attributes display in the Property Editor.

Figure 7-8 Report Group Attributes in the Property Editor

As shown below, the same component can present both normal or grouped results. When developers configure Group columns in a particular usage, the Report Group template automatically participates to format the output. The figure shows side-by-side usages of the same template component. On the left, no columns in the data source have been configured for grouping. On the right, the Group setting on the DNAME and DEPTNO columns has been enabled, and their values used for the component's group attributes Group Name and Group ID.

Figure 7-9 Template Component Without and With Grouped Data

7.1.8 Configuring Pagination Support#

For a template component available as a Multiple (Report) region, you configure whether users view additional results beyond the first screenful by scrolling or paging. This works both for normal and grouped results.

When you choose to page through results, users see a page at a time showing the number of rows you configure. The figure below shows results from the EMP table when configured to show five (5) rows per page. The usage on the right is configured to group the data by departments.

Figure 7-10 Normal and Grouped Data with Pagination

7.1.9 Enabling Row Selection#

If you make your template component available as a Multiple (Report) region, enable row selection by checking Has Row Selection Support in the Standard Attributes section of the edit page.

When this setting is on, the Property Editor displays the Row Selection section shown below. A developer using your component can enable single row selection, multiple selection, or focus-only selection, and optionally provide the name of a page item to store the selected row primary keys. For multi-row selection, the value stored in the Current Selection Page Item uses a colon (:) to delimit multiple values.

Figure 7-11 Row Selection Settings on Template Component Available as Multiple (Report)

In the figure below, the Grouped Name/Value Pairs template component appears twice. Both instances are configured to show ENAME and SAL and to use pagination with five rows per page. The instance on the right has also configured DNAME and DEPTNO as the group name and group id. The end user has selected a single row in the template component on the left, and multiple employees in the one on the right. Notice the messages "1 employee selected" and "2 employees selected". The developer configured the component's Entity Title settings to use "employee" for the Singular and "employees" for the Plural to make the selection message more user-friendly.

Figure 7-12 Single & Multiple Selection Showing Entity Title

The page contains a Handle Selected Emps page process using the PL/SQL code below to iterate over the selected employees by "splitting" the colon-delimited primary keys in the P26_SELECTED_EMPLOYEES page item. If no employees were selected, it adds a translatable error message using the text message key SELECT_AT_LEAST_ONE_EMP. If some employee primary keys were processed, then it uses the GET_MESSAGE() function in the APEX_LANG package to retrieve a translatable text message to assign to the hidden P26_SUCCESS_MESSAGE page item. If a single row was processed, it uses the message with key PROCESSED_ONE otherwise it uses the key PROCESSED_MANY. The page process references this dynamically computed success message as &P26_SUCCESS_MESSAGE. in its Success Message property.

declare
    l_processed apex_t_varchar2;
begin
    for cur_emp in
       (select ename, empno
          from emp
         where empno in
            (select column_value
               from apex_string.split_numbers(
                  :P26_SELECTED_EMPLOYEES,':')))
    loop
        apex_string.push(l_processed,cur_emp.ename);
        -- Process cur_emp.empno employee here
    end loop;
    -- SELECT_AT_LEAST_ONE_EMP => "Please select at least one employee"
    if l_processed is null then
        apex_error.add_error(p_error_code       => 'SELECT_AT_LEAST_ONE_EMP',
                             p_display_location => apex_error.c_on_error_page,
                             p_page_item_name   => null);
    else
        -- PROCESSED_ONE  => "Processed employee %0 successfully"
        -- PROCESSED_MANY => "Successfully processed employees %0"
        :P26_SUCCESS_MESSAGE := apex_lang.get_message(
                                   'PROCESSED_'||
                                   case l_processed.count
                                   when 1 then 'ONE' else 'MANY' end,
                                    apex_t_varchar2('0',
                                      apex_string.join(l_processed,', ')));
    end if;
end;

The figure below shows the three different situations the end user might encounter upon clicking the Process Selected Employees button. In the first example, with no employees selected, the user sees an error requesting that they select at least one. In the second example, after selecting a single employee they see a message containing the singular name that was processed. In the third example, they see a message listing all the employees processed.

Figure 7-13 Processing Zero, One, and Multiple Selected Rows

7.1.10 Attribute Scopes and Availability to Templates#

You assign a scope of Component, Report, or Report Group to each custom attribute.

The scope determines the templates in which you can reference its value. The table below lists which templates can use attributes of each scope.

Table 7-1 Attribute Scopes and Availability in Templates

Scroll horizontally to view the full table
Scope Available in Templates
Component Partial
Report Partial, Report Row, Report Body, Report Group, Report Container
Report Group Report Group

The figure below shows the custom attributes of a Grouped Name/Value Pairs template component, with attributes of each scope type. The Name and Value attributes are Component-scoped. The Title attribute is Report-scoped, while Group Name and Group ID are scoped to the Report Group.

Figure 7-14 Attributes of Different Scopes in Grouped Name/Value Pairs Component

7.1.11 Action Positions and Action Templates#

If your template component presents a single row or multiple rows of data, it can also define action positions. These are row-specific slots where teammates using the component can define buttons or menus to perform actions on a specific row.

After naming your action position, you include it in your Partial or Report Row template with the #ACTIONPOSITIONNAME# syntax. Each action position references a corresponding action template that defines the HTML markup for the button or menu option.

The figure below shows the Rendering tab for the native Content Row template component after defining an Actions menu in the Primary Actions action position. The menu defines several submenu options, including the Invoice Complete one selected.

Figure 7-15 Defining Menu and Submenu Options in an Action Position

At runtime, end users see the actions in the action position for each row rendered. In the figure below, two invoices appear in the Content Row region and the end user is selecting the Invoice Complete menu option on the first invoice displayed.

Figure 7-16 End User Choosing a Template Component Row Action

7.1.12 Defining Files and File URLs to Load#

If your component uses Cascading Style Sheets (CSS) or JavaScript, store them in separate component files to improve maintainability.

For example, consider a Grouped Name/Value Pairs component that defines the following CSS rule in a file named component.css:

li.is-selected {
    background-color: #e0f0ff;
    color: #003366;
}

You create the file in the Files tab of the template component edit page shown below. As shown below, APEX automatically creates a smaller "minified" version of CSS and JavaScript files whenever you save or modify them. The Reference column in the file list provides the filename to reference in the File URLs to Load tab, where you explicitly list which component files should be loaded when the component is used on a page. List them using the Reference string for the file, one per line.

Figure 7-17 Files List for a Template Component

7.2.1 Tracking Employee Training Status#

Suppose your application users need to track the status of an employee's training that progresses from Enrolled to In Progress to Completed to Certified.

The data model shown below stores employees who enroll in a course, including the status of their training that can be ENROLLED, IN_PROGRESS, COMPLETED, and CERTIFIED. It shows the familiar EMP table with a related EMP_TRAINING table for trainings an employee undertakes, and an EMP_COURSE table related to each training.

Figure 7-18 Additional EMP Tables Tracking Training Course Progress

You could use an Interactive Report region like the one below to show the status of employee training, using the Action > Format > Control Break to visually group the data into separate courses. The figure shows a Vector Search source with five employees in various stages of completion.

Figure 7-19 Employee Training Status Using Interactive Report

However, showing the status of ongoing tasks is something a Kanban Board would be great for. Ideally, you could find an existing plug-in that would let you show your data like the UI mockup below. The diagram shows four vertical "columns" representing the Enrolled, In Progress, Completed, and Certified training statuses, and two horizontal "lanes" representing different Vector Search and AI Features courses. Employee tiles appear in each cell of the grid, representing the status of the training they must complete.

Figure 7-20 Kanban Board Mockup Showing Employee Training Status

7.2.2 Downloading and Importing a Plug-in#

You can download and import plug-ins to add specific functionality to your application.

Searching the Plug-ins tab on https://apex.world for kanban, the Material Kanban Board plug-in shown below appears. Clicking its download link and unzipping the archive, you find its region_type_plugin_material_kanban.sql export file. The figure shows the plug-in details page on the apex.world site for the Material Kanban Board plug-in.

Figure 7-21 Kanban Board Plug-in on apex.world

To import the plug-in into your app, visit the Shared Components > Plug-ins list page and click the (Import) button. Choose the region_type_plugin_material_kanban.sql export file you downloaded, and click (Next) to complete the import. The figure shows the Import dialog after selecting the plug-in SQL file. Notice the Plug-in option is selected in the File Type radio group.

Figure 7-22 Importing a Plug-in Into Your Application

7.2.3 Configuring the Kanban Plug-in#

Once you install the plug-in, it shows in the list of region types you can create in Page Designer.

The figure below shows the new Material Kanban Board region on the page and the plug-in's ConfigJSON settings. Following the directions in the plug-in's documentation, you define four columns with appropriate status title and icon using the JSON format. They reflect the Enrolled, In Progress, Completed, and Certified statuses your application needs. Since you plan to use the grouping feature, you also set groupExtension to true.

{
    "staticColumns": [
       {"COLUMN_ID": "1",
        "COLUMN_TITLE": "Enrolled",
        "COLUMN_ICON": "fa-calendar"},
       {"COLUMN_ID": "2",
        "COLUMN_TITLE": "In Progress",
        "COLUMN_ICON": "fa-head-microchip"},
       {"COLUMN_ID": "3",
        "COLUMN_TITLE": "Completed",
        "COLUMN_ICON": "fa-graduation-cap"},
       {"COLUMN_ID": "4",
        "COLUMN_TITLE": "Certified",
        "COLUMN_ICON": "fa-certificate"}],
    "groupExtension": true,
    "groupColWidth": 10
}

The figure highlights the ConfigJSON setting of the Material Kanban Board region selected in the component tree in Page Designer.

Figure 7-23 Defining Kanban Board Status Columns and Icons

Then as shown below, you write a SQL Query that defines the information the Kanban board will display. The SQL query joins the EMP_TRAINING, EMP_COURSE, and EMP tables to retrieve key details about the courses and employees in training.

Figure 7-24 Configuring the Kanban Region's SQL Query

This particular plug-in uses the column names in the SQL Query you configure to identify the role each column plays in the Kanban board display. The query appears below. Notice the column aliases for the TITLE of the elements to display and the GROUP_TITLE that defines different "swim lanes" of related elements. Here, the items being displayed are ENAME values of each employee taking a course, and the course name provides the group title. Finally, COLUMN_ID in the SELECT list is the sequential column number you defined in the JSON configuration above corresponding to the different status values an employee training can have.

SELECT
    t.id AS ID,
    e.ename AS TITLE,
    case t.status
        when 'ENROLLED'    then 1
        when 'IN_PROGRESS' then 2
        when 'COMPLETED'   then 3
        when 'CERTIFIED'   then 4
    end AS COLUMN_ID,
    c.id   AS GROUP_ID,
    c.name AS GROUP_TITLE
FROM
   emp_training t
   join emp e using (empno)
   join emp_course c on t.course_id = c.id
order by c.name

With these two configurations done, you can run the page to see the employee training status at a glance in your new Kanban board. With a small amount of additional PL/SQL code, you can enable end users to change the status of an employee's training with drag and drop. The figure shows the employees in various stages of their assigned trainings, split into a different "lane" for each distinct course.

Figure 7-25 Kanban Board Region Plug-in Shows Employee Training Status