How to Adapt a Pattern for Your Application

Introduction

When creating interfaces in Appian, there are many components and layouts to choose from. With all of these configuration options, it can be hard to know what will be the right fit for your use case. To help you get inspired, there is a wide range of example patterns in the interface palette and documentation that represent the best designs for functionality and user experience.

Many patterns rely on interacting with a set of data. For these patterns to work, we include sample data. This page explains how to make patterns work with your data rather than the sample data.

There are two types of sample data found in patterns:

  • Hard-coded: Typically seen on patterns with editable form fields. These hard-coded values are stored as local variables.
  • Queried: Typically seen on patterns that display charts or read-only grids. These values are brought in with a!queryEntity() and stored in local variables.

We will go through how to swap out both hard-coded and queried data using two patterns. We'll convert the hard-coded data pattern to work with a purchase request use case. For the queried data pattern, we will work with the built-in employee use case to aggregate data from different fields than those used in the original pattern.

In both of these examples, our use cases have a flat custom data type. After we have gone through swapping out example data, we will discuss modifying a pattern to fit a nested custom data type. See Custom Data Type Design Guidance for more information on flat and nested CDTs.

Swap out hard-coded data

In this first example, we will be using the add, edit, and delete data in an inline editable grid pattern to swap out hard-coded example data. This data is being used to provide pre-populated fields in an editable grid. Editable grids are frequently used in forms, so we will walk through taking out the hard-coded employee data and converting it to be used in a purchase request interface. This interface can later be used in a process model to save the purchase requests to a data store entity.

screenshot of the editable grid created by the example pattern

The example employee data is represented in this pattern as a hard-coded array of dictionary data stored in a local variable:

1
2
3
4
5
local!employees: {
    { id: 1, firstName: "John" , lastName: "Smith" , department: "Engineering" , title: "Director" , phoneNumber: "555-123-4567" , startDate: today()-360 },
    { id: 2, firstName: "Michael" , lastName: "Johnson" , department: "Finance" , title: "Analyst" , phoneNumber: "555-987-6543" , startDate: today()-360 },
    { id: 3, firstName: "Mary", lastName: "Reed" , department: "Engineering" , title: "Software Engineer" , phoneNumber: "555-456-0123" , startDate: today()-240 },
  },

This hard-coded data is similar to what would be found in a custom data type (CDT). For our purchase request use case, we'll set up a CDT named purchaseRequestItems with the following fields and data types:

  • id (number (integer)) - The ID of each purchase request.
    • Make sure to set this as the primary key and check the Auto-generate the next unique identifier when new records are written to a data store entity box.
  • summary (text) - Describes the purchase request, such as the item name.
  • quantity (number (integer)) - How many of the requested item.
  • unitPrice (number (decimal)) - How much each item costs.
  • department (text) - Which department needs the requested item.
  • dueDate (date) - When this item needs to be received by.

Once we have a CDT, we can start configuring the pattern:

  1. Add a rule input with a CDT array as the data type. We are using a rule input instead of a local variable because the editable grid will be passing data into a process model. screenshot of the Edit Interface Input dialog
  2. Deletelocal!employees and make sure to remove all of the hard-coded data in that local variable . You will get an error message: screenshot of an error, which reads, "Could not display interface. Please check interface definition and inputs. Interface definition: Expression evaluation error: Invalid variable(s) found: local!employees".
  3. Replace all referneces to local!employees in the expression with the newly created rule input. Ctrl+H/Cmd+H is an extremely useful keyboard shortcut that will do this in one step. screenshot of the find and replace behavior in expression mode

After we replace all the references to local!employee, we'll see our form again. It's still configured to collect employee information so we'll need to update the individual interface components.

Making sure the interface components work with your data

Unlike going from a hard-coded local variable to a rule input, the steps required to modify the interface components are going to be unique for each pattern and each use case. Instead of explaining what needs to be done step-by-step, we'll address three high level things that should be changed.

1. Modifying the grid columns

Change the column labels and sortFields to correspond to the fields in your rule input.

screenshot of an empty editable grid with columns for "first name", "last name", "department", "title", "phone number", and "start date".

screenshot of an empty editable grid with columns for "summary", "quantity", "unit price", "department", and "due date"

2. Change the interface components

The interface components used to populate the employee grid need to change to match the labels and types we used for each field when we set up our CDT.

For example, the first name column in Employee:

1
2
3
4
5
6
a!textField(
  label: "first name " & fv!index,
  value: fv!item.firstName,
  saveInto: fv!item.firstName,
  required: true
)

changed to the summary column in our updated editable grid:

1
2
3
4
5
6
a!textField(
  label: "Summary " & fv!index,
  value: fv!item.summary,
  saveInto: fv!item.summary,
  required: true
)

You will need to change the interface components for the quantity and unitPrice fields to number(integer) and number(decimal) components.

3. Clean up the remaining expression

For the last part of our update, we will clean up formatting and a few areas of the expression, including:

  • Changing the form layout's label to Add Items to Purchase Request.
  • Changing the editable grid's addRowlink parameter label to Add Item.
  • Updating the form and submit button's label to SEND TO REVIEW.
  • Removing the a!localVariables() function since there are no remaining local variables.

These steps will be unique for every pattern configuration. But the high-level steps will be similar for any pattern you are trying to modify.

Try adding a few rows of items and data to test out the grid. Your interface should looks like this:

screenshot of the final editable grid for the purchase request interface

Now that we have configured the pattern to work with our use case, it can be used in a process model, either through a start form or as a task in a workflow.

Swap out queried data

When you are developing your own applications, at some point you will probably need to query a data store entity to retrieve your data. Queries allow you to use and display the data in your data store entity in interfaces with components such as charts and grids or in layouts, like reports and dashboards.

Patterns with queries provide examples of different ways that you can display your data using a!queryEntity(). When you are adapting these patterns to use your own data store entities, you will need to replace the pattern's example query with one of your own.

In this example, we will be adapting the Aggregate Data from a Data Store Entity by Multiple Fields and Display in a Chart pattern to display the total number of employees hired each year in each department. Though we will change the query aggregation, we will still use the EMPLOYEE_ENTITY that this pattern comes with.

If you have not already created the EMPLOYEE_ENTITY, follow the steps on Use the Write to Data Store Entity Smart Service Function on an Interface to set up your entity and add data.

image of the example pattern's stacked column chart with 5 columns

Changing query data using the query editor

When we were replacing hard-coded data, we simply removed the local variable pattern and replaced it with a rule input. Here, we will use the query editor to modify local!datasubset to perform query aggregations on three fields. These aggregations will group our data by department and the year each employee started.

To get started with your pattern and the query editor:

  1. Copy and paste the pattern into EXPRESSION MODE.
  2. Switch to DESIGN MODE.
  3. In the COMPONENT CONFIGURATION pane, hover over local!datasubset and click the LAUNCH QUERY EDITOR icon.

To configure Paging & Sorting:

  1. Under Paging & Sorting, keep the default Basic option selected.
  2. In Show, select All Rows.
  3. In Sort By, select department. Keep In Ascending Order selected as the default setting.
  4. Click Add Sort.
  5. In Then Sort By, select startDate_year. Keep In Ascending Order selected as the default setting.

To configure the query aggregation:

  1. Under Query Results Preview, click REMOVE GROUPING. This will allow us to replace the pattern's groupings with our own aggregations.
  2. Click REMOVE, then click GROUP DATA.
  3. In Select a field to group by, enter department. Then click GROUP.
  4. Under the Fields list, select id. After it's selected, the field appears as id_count because the aggregation is calculating the total number of employees in each department by counting the IDs.
  5. Click TEST QUERY. Now you can see the number of employees in each department.
  6. Under the Fields list, select startDate. After it's selected, the field appears as startDate_year because the aggregation is grouping the date that each employee started by only the year.
  7. Click TEST QUERY. Now you can see the number of employees that started in each year by the department.
  8. Click GENERATE QUERY.

To change the data store entity for your query while in the query editor, click CHANGE DATA STORE ENTITY in the bottom left corner of the query editor. Then select your data store entity and click CONTINUE.

screenshot of the query editor with aggregations on the department, id, and start date fields.

Clean up the remaining expression

Now that we have set up the query aggregation to group the data from the fields that we want using the query editor, it's time update a few areas of the expression.

In EXPRESSION MODE:

  1. Replace local!labels: index(local!datasubset.data, "title", {}), with local!labels: index(local!datasubset.data, "startDate_year", {}),.
  2. Replace index(index(local!datasubset.data, "id", {}), local!intersection, 0) with index(index(local!datasubset.data, "id_count", {}), local!intersection, 0).

You're now done configuring the chart to work with the new query aggregations that we set up. Your chart should look like this:

screenshot of a stacked column chart displaying the total number of employees hired each year by each department

Dealing with nested values

In our previous two examples, we've gone from one flat data type to another. We will now go through what you should do if you if you want to adapt an interface pattern that references a nested CDT value.

For example, let's say that the department and title fields in our employee CDT live in nested CDTs. When we go to query the data our expression would look something like this:

1
2
3
4
5
6
7
a!querySelection(columns: {
   a!queryColumn(field: "firstName"),
   a!queryColumn(field: "lastName"),
   a!queryColumn(field: "position.department"),
   a!queryColumn(field: "position.title")
  }
)

It is a best practice to use the alias parameter in a!queryColumn() to make referring to nested or aggregated values easier in an interface expression.

When adapting patterns to work with CDTs with nested values, it is important to understand the data model of the CDTs that you are dealing with. For example, a customer CDT might have fields for billing and shipping addresses that are nested CDTs. The nested CDT for addresses would have a many-to-one relationship with the parent customer CDT. This means that one address could be used for a company's billing address, shipping address, or both. That same address could also be used for the billing and shipping addresses of many other companies.

If we wanted to display all the customers' billing and shipping addresses in a read-only grid, we would reference the address fields with a query using fv!row.ShippingAddress.Address or fv!row.BillingAddress.Address. An example of two grid columns is shown below:

1
2
3
4
5
6
7
8
9
10
     a!gridColumn(
        label: "Shipping Address",
        sortField: "ShippingAddress.Address",
        value: fv!row.ShippingAddress.Address
      ),
      a!gridColumn(
        label: "Billing Address",
        sortField: "BillingAddress.Address",
        value: fv!row.BillingAddress.Address
      )

Now you are ready to start adapting patterns to your own unique data. Whether you need to switch out hard coded data, create query aggregations, or configure examples to use nested CDTs, you're prepared to make Appian's many patterns work for you.

Open in Github

On This Page

FEEDBACK