How To: Bring Your Own AG Grid

Prev Next

Overview

This how-to guide details how to create a custom (Bring Your Own) AG Grid component. This BYO Unqork component embeds a customizable AG Grid data table in Express View. It also acts as a wrapper, translating Unqork's data format into a format that the AG Grid library can understand and interact with.

To learn more about AG Grid, view the AG Grid website: https://www.ag-grid.com/.

The Bring Your Own feature is intended for developers who have a strong understanding of the Unqork Designer Platform and JavaScript.

BYO AG Grid Component Ideation

For this example, the fictional client company "ABC" wants to implement an AG Grid data table to use as a custom Unqork component. The component must allow Creators to create multiple columns that contain a key and label field.  They also want the component to accept a string containing an array of objects with table data. Additionally, the company wants a custom event that emits when a user clicks on an AG Grid’s cell.

As the developer assigned to this task, break down and document the client's ask into actionable sections:

  • Asset Types: What’s needed to meet the client's requirements of an averaging and rounding asset?

    • Component(s): Does the client's request require the creation of something not currently supported in the Unqork platform?

    • Event(s): Does the asset need to emit an event when it's used? What action should emit the event?

    • Operation(s): Does the asset need to be manipulated by other elements using an operation?

  • Inputs & Outputs: Catalog a list of potential inputs and outputs for the asset. Events are typically an output in this list.

  • Naming Scheme: Develop a naming scheme for the asset that aligns with Unqork values and avoids conflicts with potential future custom assets.

    To understand naming scheme limitations, view the Important callout in the overview of our Bring Your Own (BYO): Understanding the manifest.json File article.

Now that the client has described the ask, create a document detailing all the potential elements the operation asset requires.

Example Ideation Documentation

The sections below detail the product requirements that meet the client's request. Developers use this information to implement the component’s JavaScript, create the manifest file and package, then package it to the Unqork Designer Platform.

Component(s)

A custom Unqork component that imports an AG Grid data table.

Component Name

Description

AG Grid

An imported AG Grid with the following configuration settings:

  • Key (Field): Maps the Value field’s to the AG Grid column.

  • Label (Field): The header displkay value for the column.

  • Value (Field): Accepts an Array of table data.

Event(s)

An event used as part of the Events & Operations Builder.

Parameter

Object Type

Description

AG Grid Cell Clicked

agGridCellClicked

An event that emits when an end-user clicks on an AG Grid Cell. The event includes a payload with the cell value.

Input(s)

Creators use the input fields to map and label columns.

Parameter

Object Type

Description

columnDefinitions

array

An array of objects that defines the grid's columns. The columns definition contains the following keys:

  • key: Maps the table data from the value field to the column.
    Corresponds to the Key field in the component’s configuration drawer.

  • label: Creates a header display value.
    Corresponds to the the Label field in the component’s configuration drawer.

value

string

A JSON string that represents the data for the grid's rows.

Corresponds to the Value field in the component’s configuration drawer.

Libraries

This component imports the AG Grid library for rendering table data. See examples of importing an AG Grid in their Get Started documentation: https://www.ag-grid.com/javascript-data-grid/getting-started/

Library Name

Description

Documentation Link

AG Grid

A free, open source library that provides a high-performance, feature rich, and fully customizable Data Grid  

https://www.ag-grid.com/

Naming Scheme

Verify all naming values do not conflict with existing Unqork assets, or other custom assets in the environment.

IMPORTANT

Unqork does not enforce programmatic name spacing for custom asset types. All type values for components, operations, and events must be globally unique. If multiple custom assets share the same type, or if a custom asset uses a type that conflicts with a native Unqork type, the runtime will render or execute only the first matching definition. Doing so leads to unpredictable behavior, asset shadowing, or broken functionality—especially when bundling or importing multiple packages.

It is the responsibility of the developer to ensure type uniqueness to prevent collisions. Component, operation, and event types require a unique name to avoid collision issues.

To avoid namespace issues, prefix custom components with a name unique to your company or application. For example, if a company named ABC creates a Card Panel component. The component's name space could be abcCardPanel.

Asset Type

Asset Name

Naming Scheme

Component

Ag Grid

exAvgAndRound

Event / Output

AG Grid Cell Clicked

agGridCellClicked

Input

Column Definition

columnDefinitions

Input

Value

value

Create the manifest.json File

The manfest.json file serves as the contract between Unqork and the AG Grid implementation. In this file, you’ll specify the AG Grid components and event properties.

{
  "name": "AgGrid",
  "version": "1.0.0",
  "main": "agGrid.js",
  "type": "custom",
  "productType": "BYO",
  "description": "AG Grid integration with Unqork",
  "components": [
    {
      "name": "AG Grid",
      "type": "agGrid",
      "description": "AG Grid component for Unqork",
      "model": {
        "type": "object",
        "properties": {
          "columnDefinitions": {
            "name": "Column Definitions",
            "type": "array",
            "description": "Column definitions for this grid (currently only supporting key and label)",
            "items": {
              "type": "object",
              "properties": {
                "key": {
                  "type": "string",
                  "description": "Unique key for the column"
                },
                "label": {
                  "type": "string",
                  "description": "Display label for the column"
                }
              }
            }
          },
          "value": {
            "name": "Grid Data (JSON)",
            "type": "string",
            "description": "JSON string of data for the grid"
          }
        },
        "required": ["columnDefinitions"]
      },
      "events": [
        {
          "name": "AG Grid Cell Clicked",
          "type": "agGridCellClicked",
          "description": "This event is triggered when the user clicks on a grid cell.",
          "stability": "STABLE"
        }
      ]
    }
  ]
}

The following fields are used at the root level of the manifest:

Field

Type

Required

Description

name

string

Checked Box Icon

A unique identifier for the package. For example, MyCompanyNameAssets.

version

string

Checked Box Icon

The semantic version number. For example, 1.0.0.

main

string

Checked Box Icon

The relative path to the JavaScript entry file. For example, agGrid.js.

type

enum

Checked Box Icon

The package type. Currently, the only supported value is custom.

productType

enum

Checked Box Icon

The target platform feature. Currently, the only supported value is BYO.

description

string

Checked Box Icon

A description that displays in the Admin Panel after installation.

components

array<component-description>

Optional

A list of component definitions included in the package.

events

array<event-description>

Optional

List of event definitions.

Understanding the components[0] definition.

This is the main definition for the AG Grid component itself. This definition includes the name, inputs, and events for the asset.

Property

Description

name and type

Define the component's name and its internal identifier. The type (agGrid) must match the export name in the JavaScript file (agGrid.js) so Unqork can link the JSON definition to the correct code.

model

This object defines a custom event. It exports a model that describes the structure of the event's payload (name and type). Doing so lets other parts of the Unqork platform use and understand the event that the component emits.

columnDefinitions

This is a required property that defines the columns of the grid. The schema specifies that it must be an array of objects, where each object has a key (for internal use) and a label (for display).

value

This property is where the grid's data is provided. The schema expects a JSON string to define the rows of the grid.

events

This section defines the custom events the component can emit.

name and type

These define the agGridCellClicked event's name and its unique identifier.

description

Explains when the event is triggered.

stability

The STABLE tag indicates that this event's API is reliable and will not change without warning.

Implement the AG Grid Component

For this example, create a file called agGrid.js. In this file, create an component that does the following:

  1. Creates a Shadow DOM as a part of the BYO implementation requirements.

  2. Initializes the Unqork Runtime API as a part of the BYO implementation requirements.

  3. Subscribes to column definitions, updating the Express View rendering to match.

  4. The component subscribes to state changes for the grid's value property, automatically updating the component to reflect any changes configured in the Module Builder.

  5. Emits an event (onAgGridCellClicked) back to the Unqork runtime. Creators can configure the event using the Operations Builder to trigger downstream logic.

  6. Validates input data and parses it as JSON. Reducing inconsistencies with Unqork’s platform.

  7. Map’s Unqork’s input format to AG Grid’s input format.

  8. Exports and render’s the AG Grid data into the Unqork Designer platform.

Review the code example below for more information on each method:

The comments in the JavaScript below are written in the JSDoc format. For more information on JSDoc block tags (@param, @return), visit the JSDoc website: https://jsdoc.app/.

// AgGrid Import //
// See import examples in AG Grid's Get Started Documentation: https://www.ag-grid.com/javascript-data-grid/getting-started/

class UnqorkAgGridComponent extends HTMLElement {
  constructor() {
    super()
    this.attachShadow({ mode: 'open' })

    this.gridOptions = {
      columnDefs: [],
      rowData: [],
      
    }
  }

  /**
   * This is the only required method to integrate with the Unqork system
   * 
   * @param {*} api The interface to the Unqork Runtime, used for both
   *                monitoring state and emitting events
   */
  initialize(api) {
    this.config = api.state.currentState()
    this.api = api

    if (this.config.columnDefinitions?.length) {
      const defs = this._normalizeInput(this.config.columnDefinitions)
      this.gridOptions.columnDefs = this._formatColumnDefinitions(defs)
    }

    if (this.config.value?.length) {
      this.gridOptions.rowData = this._normalizeInput(this.config.value)
    }

    this.renderGrid(this.shadowRoot, this.gridOptions)
    this.subscribeColumnDefs()
    this.subscribeData()
  }

  /**
   * Subscribe to the source for column definitions
   * 
   * This can be made more robust by first using
   * api.state.state$('columnDefsReference') to subscribe to
   * any changes to that value (i.e. the target key), and then using
   * resolveByKey$ to resolve the current value of that key.
   */
  subscribeColumnDefs() {
    this
      .api
      .state
      .state$('columnDefinitions').subscribe((columnDefs) => {
        console.log('AG Grid column definitions updated to', columnDefs)
        // This _should_ be an array, but sometimes components try to set it as a
        // JSON string instead, so we handle that here
        const value = typeof(columnDefs) === 'string' ? JSON.parse(columnDefs) : columnDefs
        this.gridOptions = {
          rowData: this.gridOptions.rowData,
          columnDefs: value ? this._formatColumnDefinitions(value) : [],
        }
        this.updateGrid(this.gridOptions)
      })
  }

  subscribeData() {
    this.api.state.state$('value').subscribe((rowData) => {
      console.log('AG Grid value updated to', rowData)
      // We support setting this as a JSON string or already parsed array of objects
      // so handle that here
      const value = typeof(rowData) === 'string' ? JSON.parse(rowData) : rowData
      this.gridOptions = {
        rowData: value || [],
        columnDefs: this.gridOptions.columnDefs,
      }
      this.updateGrid(this.gridOptions)
    })
  }

  updateGrid(gridOptions) {
    console.log('Updating AG Grid', gridOptions)
    this.gridApi.updateGridOptions(gridOptions)
  }

  async renderGrid(document, gridOptions) {
    console.log('Rendering AG Grid component', {gridOptions, agGrid, windowAgGrid: window.agGrid})

    document.innerHTML = this.view()
    this.gridEl = document.querySelector('#myGrid')
    this.gridApi = window.agGrid.createGrid(this.gridEl, gridOptions)

    // Set this here so that it doesn't overridden when we update gridOptions
    this.gridApi.addEventListener('cellClicked', (ev) => {
      console.log('Emitting AG Grid Cell Clicked Event', ev)
      this.emitCellClickedEvent(ev)
    })

    console.log('Created AG Grid', {
      document,
      gridOptions,
      gridEl: this.gridEl,
      gridApi: this.gridApi,
    })
  }

  // Emit an event when a cell is clicked
  // Full docs: https://www.ag-grid.com/javascript-data-grid/grid-events/#reference-selection-cellClicked
  emitCellClickedEvent = (ev) => {
    this.api.events.emit({
      name: 'onAgGridCellClicked',
      payload: ev
    })
  }

  view() {
    return `
      <div id="myGrid" style="height:500px"></div>
    `
  }

  /**
   * Input data can be either JSON string or actual data, due to
   * Unqork data constraints, so ensure it's proper data before
   * using
   */
  _normalizeInput(val) {
    return typeof(val) === 'string' ? JSON.parse(val) : val
  }

  /**
   * We store column definitions with standard key/label properties
   * But AG Grid using different property names, so we map it here
   */
  _formatColumnDefinitions(defs) {
    return defs.map(({key, label}) => {
      return {
        field: key,
        headerName: label ?? key
      }
    })
  }
}

// This definition defines the state settings (model) for this component
// It mirrors the fuller description in manifest.json and will
// eventually be used to auto-generate the manifest.json JSON schema
class AgGridDefinition {
  columnDefsReference
  dataReference
}

// Actual export that exposes both the view layer and the model
// and is consumed by the Unqork Runtime for both configuration and
// execution
// All of these are `async` to allow for us to load them on demand
// without impacting initial page load performance
export const agGrid = {
  model: async () => AgGridDefinition,
  view: async () => UnqorkAgGridComponent,
}

// This definition describes the schema of the event that is emitted
// when the user clicks on an item
class CellClicked {
  name = 'agGridCellClicked'
  payload = {
    index,
    text,
  }
}

// This export is used to expose the event to the Unqork Runtime
export const agGridCellClicked = {
  model: async () => CellClicked,
}    

Understanding UnqorkAGGridComponent  Class

This is a web component that encapsulates all the AG Grid functionality.

Method

Description

constructor()

Sets up the component's internal state, including the Shadow DOM to isolate its styles and markup. It also initializes a base gridOptions object, which will be populated with data from Unqork.

initialize(api)

The required method for Unqork integration. The Unqork Runtime calls this method to provide the component with the api object. This is where the component gets its initial data from Unqork's state and sets up subscriptions to listen for future changes.

subscribeColumnDefs()

Listens for changes to the columnDefinitions property via Unqork's state management. This ensures that the grid's columns can be updated dynamically if a creator changes the data source. It also handles parsing the input if it's a JSON string.

subscribeData()

Listens for changes to the value property, which holds the grid's data. When the data changes, this method updates the grid's rows, allowing for real-time updates. It also includes logic to handle both string and array inputs.

renderGrid(document, gridOptions)

Handles the initial rendering of the AG Grid. It creates the HTML container for the grid, uses the AG Grid library (window.agGrid) to create the grid instance, and sets up a cellClicked event listener.

updateGrid(gridOptions)

A helper function that calls AG Grid's internal API to update the grid's configuration, which is used by the subscription methods to apply changes.

emitCellClickedEvent(ev)

This method is the component's output. It uses the Unqork Runtime's api.events.emit() function to send a custom event (onAgGridCellClicked) when a user clicks a cell in the grid.

This allows other components or workflows in Unqork to react to the click.

_normalizeInput(val)

A utility method that checks if the input value is a string and, if so, parses it as JSON. This handles inconsistencies with how data might be stored in the Unqork platform.

_formatColumnDefinitions(defs)

A helper method that translates the Unqork component's input format using the key and label properties into the format that AG Grid requires (field and headerName).

Understanding the agGrid and agGridCellClicked Exports

These exports serve as the component’s manifest, providing the Unqork runtime with the necessary data to use the component.

Class

Description

agGrid

This object exports the model (the component’s data schema) and the view (the component itself). The Unqork platform uses this to configure the component's properties and render it correctly.

agGridCellClicked

This object defines a custom event. It exports a model that describes the structure of the event's payload. For example, the name and payload when a grid cell is clicked. Doing so lets other parts of the Unqork platform use and understand the event that the component emits.

Create the BYO Component Package

After the asset JavaScript and manifest.json files are complete, compress them into a BYO package.

To compile a file using Terminal (Mac) or Command Prompt (Windows):

  1. Using the command line prompt, navigate to the directory containing the agGrid.js and manifest.json files. For example, cd C:\Users\UserName\Desktop\agGrid.

  2. Execute the following command: tar -cvzf agGrid.tar.gz manifest.json agGrid.js.
    Terminal window showing commands to create a tar.gz file from project files.

The agGrid.js file and manifest.json add to the tar.gz file in the same folder they're located in.

NOTE

The steps above use the tar command and the following options:

-c: Creates a new archive.

-z: Compresses the archive using gzip.

-v: Lists the files in the command line as they are added to archive.

-f: Specifies the file name for the archived files.

Upload the BYO Operation Package

After creating the agGrid.tar.gz package, upload it to the Unqork Designer Platform using the Custom Assets Administration page:

  1. From the UDesigner homepage, click Administration.

  2. Under Assets, click Custom Assets Administration.

  3. Click + Create New. The Create Asset modal displays.

  4. Under File Upload, click or drag the BYO Operation package from your local device to the upload window.

  5. Click Scan File. The package details display.
    Create asset form for AgGrid version 1.0.0 with successful scan notification.

  6. Click Review Assets.

  7. Review the asset's details, including Components, Events, and Operations.

  8. Click Confirm & Create.

  9. Review the Library Usage Acknowledgment and Liability Agreement. Click the ☐ (checkbox) to acknowledge the agreement.

  10. Click Create Asset.

The asset package displays in the Custom Assets’ Packages list. The package's individual assets display in the Assets tab's Assets list. The assets are now available in the Module Builder for all applications in the environment.

Test the AG Grid Component

Now that the BYO AG Grid component is in the Unqork Designer Platform, test its functionality in the Module Builder and Express View. This example assumes you are configuring a Vega (2.0) module.

For this example, test the following functions:

  • AG Grid Configuration Drawer: Verify each setting is functional.

  • agGridCellClicked Event: Verify the event emits when clicking cell in the grid.

Configure the Text Field Component

Use a Text Field component to receive the final value created by using the BYO agGridCellClicked event and SET_PROPERTY operation.

  1. In the Module Builder, drag and drop a Text Field component onto your canvas.

  2. In the Property ID field, enter output.

  3. In the Label Text field, enter Cell Clicked.

  4. Click Save Component.

Configure the Custom Component

The Custom Component contains a list of all BYO components in the environment. Select the AG Grid component, then configure it to test its settings, and the custom agGridCellClicked event.

  1. Drag and drop a Custom Component onto your canvas.

  2. In the Property ID field, enter byoAgGrid.

  3. From the Select Component drop-down, enter or select AG Grid. The component's configuration populates.

  4. Click the Add Item button three times to create a total of four objects.

  5. Configure each Object with the following:

    Object #

    Setting

    Value

    Object 1

    Key

    make

    Label

    Make

    Object 2

    Key

    model

    Label

    Model

    Object 3

    Key

    price

    Label

    Price

    Object 4

    Key

    electric

    Label

    Electric

  6. In the Value field, enter the following table data:

    [{"make":"Tesla","model":"Model Y","price":64950,"electric":true},{"make":"Ford","model":"F-Series","price":33850,"electric":false},{"make":"Toyota","model":"Corolla","price":29600,"electric":false},{"make":"Mercedes","model":"EQA","price":48890,"electric":true},{"make":"Fiat","model":"500","price":15774,"electric":false},{"make":"Nissan","model":"Juke","price":20675,"electric":false}]

Configure the byoAgGrid Event and Operation

While remaining in the configuration drawer, set up the BYO agGridCellClicked event to trigger a Set Property operation. Configure the operation to retrieve the current selected AG Grid cell’s value.

  1. Next to Events & Operations, click Edit.

  2. From the Select an Event drop-down, enter or select Cell Clicked. This is the BYO event defined in the agGrid.js  file.

  3. Click Add.

  4. Click + Add Operation.

  5. From the Operation Type drop-down, select Set Property .

  6. In the Target Key field, enter output. This sends the operation’s output to the output Text Field component.

  7. In the Property field, enter value.

  8. In the Value field, enter {{$event.payload.value}}. When the end-user clicks on a cell, this dynamic value updates to the clicked cell’s value.

  9. Click Save.

  10. Click Close.

  11. Click Save Component.

  12. Save your module.

Your completed module looks like the following:

BYO AG Grid component interface showing cell clicked and component options.

Preview and Test the Module

Finally, test your configuration and verify that the AG Grid table displays in Express View, and the agGridCellClicked event emits the Set Property operation.

  1. Preview your module in Express View.

  2. Verify the grid displays the table data contained in the Custom Component.

  3. In the AG Grid, click on a cell.

  4. In the Cell Clicked field, verify that the value matches the cell’s value. This verifies the agGridCellClicked  is emitting properly.

If the custom asset functions as intended, then it’s ready to be used by Creators in the development of Unqork applications.

If the Custom Operation generates errors or is missing features:

  1. Create a copy of the current package and its contents.

  2. Update the package's required files.

  3. Change the package's version number.

  4. Update the package by referring to the Package Management section in our BYO Best Practices article.