End-User Rich Text Editor Component

This component is not part of the Appian base product. It is a component plugin managed by Appian Professional Services and it can be downloaded on the Appian AppMarket.

Please see the Component Plug-in Troubleshooting Guide if you have any issues.  If you have further questions please email richtext-componentpluginsupport@appian.com.

Plugin Components

As of version 1.5.3, this plugin includes two (2) components:

  • fn!richTextField() - This is the plugin’s original component.
  • fn!richTextFieldWithTables() - This component is new as of version 1.5.3.

Refer to the chart below to understand what formatting each component supports.

Component Text Formatting Table Formatting Image Uploads
fn!richTextField() White check mark White check mark
fn!richTextFieldWithTables() White check mark White check mark

All information in this guide applies to both components, unless stated that it only applies to one of the components.

Why are there 2 components?

In order to provide table support, we needed to switch to a new underlying library that supports tables. This new library generates HTML that is different from the previous library. To prevent refactoring and unintended behavior for those using the plugin currently, we opted to keep the existing component as is If you want to migrate to the new component, refer to the How to migrate to fn!richTextFieldWithTables section below.

Also, the new component, fn!richTextFieldWithTables(), strictly uses standard HTML attributes for all formats, which should simplify complexities with passing the output HTML to downstream systems, such as email or document generation.

Parameters

Name

Keyword

Type

Applicable Component(s)

Description

Label

label

Text

Both

Optional text to display as the field label.

Label Position

labelPosition

Text

Both

Optional text to determine where the label appears. Valid values include

  • "ABOVE" (default) Displays the label above the component.
  • "ADJACENT" Displays the label to the left of the component.
  • "COLLAPSED" Hides the label. The label will still be read by screen readers.
  • "JUSTIFIED" Aligns the label alongside the component starting at the edge of the page.

Instructions

instructions

Text

Both

Optional text displayed below the field's value.

Help Tooltip

helpTooltip

Text

Both

Displays a help icon with the specified text as a tooltip. The tooltip displays a maximum of 500 characters. The help icon does not show when the label position is "COLLAPSED".

Required

required

Boolean

Both

Shows or hides the asterisk indicating if the component is required but does not enforce requiredness. To enforce requiredness, use the parameter "validations". To enforce requiredness only upon submission, use section or form-level validations.

Disabled

disabled

Boolean

Both

Determines if the user is prevented from changing the value. Default: false.

Validations

validations

Text Array

Both

Validation errors to be displayed below the field when the value is not null.

Height

height

Text

Both

Determines the field height. Valid values include "SHORT", "MEDIUM" (default), and "TALL".

Show When

showWhen

Boolean

Both

Determines whether the component is displayed on the interface. When set to false, the component is hidden and is not evaluated. Default: true.

Rich Text Value

richTextValue

Text

Both

Rich text to display in the field.

Rich Text Save Into

richTextSaveInto

Save Array

Both

One or more variables that are updated with the richText value when the user changes it. Use a!save() to save a modified or alternative value to a variable.

Read Only

readOnly

Boolean

Both

Determines if the field should display as not editable. Default: false.

Max Size

maxSize

Number (Integer)

Both

Maximum size of the HTML formatted rich text data (not number of characters). Default: 10000.

Placeholder

placeholder

Text

Both

Text to display in the field when it is empty. Does not show if the field is read only.

Enable Progress Bar

enableProgressBar

Boolean

fn!richTextField()

Whether to show the progress bar of what percent of rich text data users have entered. Default: true.

Allowed Formats

allowedFormats

Text Array

fn!richTextField()

Determines which format styles are allowed. Note: these must be set on page load and cannot change. Valid values: "header", "size", "bold", "italic", "underline", "strike", "color", "background", "link", "align", "indent", "list". Default: All styles. See more info below.

Note that fn!richTextFieldWithTables() sets this parameter to "All styles" by default on the back-end as this is the most common setting in the older component. If you'd like to parameterize allowed styles, please reach out with a request.

Table Border Style

tableBorderStyle

Text

fn!richTextFieldWithTables()

Determines the style of the grid border. Valid values: "STANDARD" (default), "LIGHT", "NONE".

Allow Images

allowImages

Boolean fn!richTextField()

Determines if images are allowed. Default: false. See more info below.

Note that fn!richTextFieldWithTables() does not support image upload at this time. If you'd like to allow this behavior, please reach out with a request.

Image Storage Connected System

imageStorageConnectedSystem

Connected System

fn!richTextField()

The instance of the Rich Text Editor Image Upload Connected System used to store images from the rich text editor. This is required if allowImages is set to true. 

Uploaded Images

uploadedImages

Map Array

fn!richTextField()

An array of images uploaded during this session with metadata about the image. "wasRemovedFromField" is true when a user uploads an image but then removes it in the same session.

Notes

  • Due to the potential large size of the HTML output of this component, do not save this value into a process variable or a node parameter. Instead, use an expression to load and persist the HTML output directly on the user interface.
  • Do not use validations to validate the maximum length of the HTML formatted rich text value. Instead, use the parameter maxSize.
  • Use validations to validate the maximum length of characters that an end-user can enter in the component. To calculate the number of characters, using the functions fn!len() and fn!striphtml().
  • When the rich text field is displayed in a read-only format, set the parameter height to AUTO for optimal results.
  • The parameter required doesn’t actually validate that the richTextValue is not null. This is a limitation of the component plug-in framework. Use section-level or form-level validations to validate the requiredness of the richTextValue.

Data Storage

Database Column Type Options

There are two options for storing the HTML output of this component in your database; the considerations of which are listed below.

 

VARCHAR column type, or equivalent

LONGTEXT column type, or equivalent

Max Size

Limits the maximum size of the HTML output to 4,000 characters (varies by database)

The maximum size of the HTML output can be as great as 50,000 characters, which is large enough to essentially be considered no limit to a user

Persistence

Designers can pass this output and the CDT with this field into process variables

It is strongly recommended to only use this option if you will be writing and reading from the database directly from SAIL interfaces; never pass data of this column type into process variables

Support

This is a standard database column type which can be exported, modified, and migrated easily

This is not a standard database column type, which could lead to difficulties when trying to export, modify, or migrate

Querying

Searching and sorting against this column type is performant (see Querying below for more information)

Searching and sorting against this column type is not performant, and might not be supported depending on your database

Querying Against The Rich Text Data

For the use case of searching or sorting against the rich text data, it is recommended to separately create a column in your CDT to store the raw text.  The raw text column should be the same type and size of the HTML column. Whenever searching or sorting against the rich text data, search or sort against this column, not the HTML column.

To populate the raw text column, there are two options:

  1. Using the fn!striphtml() function in Appian. This is best used when the size of your data is small, or when the contents of the rich text editor never hits a process variable.
  2. Using database triggers. This is best used when it's important to avoid increasing the memory consumption of the process engines, such as when the rich text editor contents are large and passed through process.

To create database triggers to update this field on every INSERT or UPDATE to the database table, follow the instructions below for accomplishing this in MariaDB. For other databases, use the same design, just adjust to match your database’s syntax.

Replace [RAWTEXT_COL] with the name of your raw text column, [HTML_COL] with the name of your html column, and [TABLE_NAME] with the name of your table.

-- Create a function to strip html tags given a string

DELIMITER &&

CREATE FUNCTION `strip_tags`($str text) RETURNS text
BEGIN
   DECLARE $start, $end INT DEFAULT 1;
   LOOP
       SET $start = LOCATE("<", $str, $start);
       IF (!$start) THEN RETURN $str; END IF;
       SET $end = LOCATE(">", $str, $start);
       IF (!$end) THEN SET $end = $start; END IF;
       SET $str = INSERT($str, $start, $end - $start + 1, "");
       SET $str = REPLACE($str, " ", " ");
   END LOOP;
END&&

DELIMITER ;

-- Create triggers to execute strip_tags() on the html column with every insert or update, and store the raw text

DELIMITER &&

CREATE TRIGGER `store_raw_input_insert`
BEFORE INSERT ON `[TABLE_NAME]`
FOR EACH ROW BEGIN
    SET NEW.`[RAWTEXT_COL]` = strip_tags(NEW.`[HTML_COL]`);
END&&

CREATE TRIGGER `store_raw_input_update`
BEFORE UPDATE ON `[TABLE_NAME]`
FOR EACH ROW BEGIN
    SET NEW.`[RAWTEXT_COL]` = strip_tags(NEW.`[HTML_COL]`);
END&&

DELIMITER ;

Sending Emails

For the use case of sending formatted emails created by end users, a designer must consider the maximum size of the HTML output as well as the expected email volume.

When sending emails with the Send Email node, the  HTML output is loaded and cached in the process execution engine as a string.  Over time, the cached values accumulate in memory and can lead to memory resource issues.

It is recommended to perform non functional testing by sending representative emails at the expected email volume for at least 3 days to measure and evaluate the impacts on the system memory usage and ensure a scalable application in production.

To configure in process, in the Send Email node, either pass the HTML output as an expression to the ad-hoc message body, or pass the HTML output as an input parameter to the HTML template message body.

Allowed Formats

Only applicable for fn!richtextfield. This parameter to the function fn!richTextField() allows the designer to configure which formatting options are available to the end users when entering rich text into the field such as “bold”, “italic”, “list”, etc.

Configuring this Parameter

For consistency and ease of development/maintenance across the platform, the allowed formats should be stored in a constant and used in all instances of the rich text editor.

Modifying Allowed Formats

Allowed format options should never be removed after users have already entered data in this field in a production setting (outside of special circumstances), since this means previously-entered text would not be backwards compatible with the updated component configuration.  For example, if a user had formatted using a numbered list, and “list” was removed as an allowed format, then all numbered lists that were previously saved would render incorrectly in the updated component configuration.

If you do need to remove some allowed formats after users have already entered text in a production setting, it is recommended to pass the previously allowed formats to the component whenever it is rendered as read-only.  For example, picture a comment thread that supported “list” for a while, then removed “list” format. The read-only fields, displaying previously-entered comments, could still support “list” while the editable field for new comments would no longer support “list”.  However, this gets more complicated when editing of previously-entered data is considered (e.g. editing an existing comment).

Image Uploads

Only applicable for fn!richTextField. To enable image uploads, you must do the following:

  1. Install the Rich Text Editor Image Upload Connected System
  2. Create a knowledge center and folder to store uploaded documents and note the new folder's UUID
  3. Create a new connected system object which leverages the Rich Text Editor Image Upload Connected System
  4. Enter the folder's UUID and the user context to use when uploading images
  5. Create a new Connected System constant which points to the new Connected System object in your application
  6. In your interface where you use fn!richTextField(), set allowImages to true and imageStorageConnectedSystem to the constant created in the previous step

Note: only the URL to the uploaded image, not the image content itself, is stored in the generated HTML from fn!richTextField().  This means that if you use the generated HTML outside of Appian (e.g., in an email), the image will not display unless the outside viewer is already logged into Appian.

Migrate Components

If you have not yet used either component, you can use whichever one suits your needs best. However, be mindful that it is non-trivial to migrate between fn!richTextField and fn!richTextFieldWithTables and the latter will likely receive more enhancements over time, as the underlying library which renders it is kept up-to-date more.

The fn!richTextField component relied on non-standard HTML attributes to provide formatting, specifically indentation and nested list formatting:

  • Indentation: fn!richTextField uses the HTML class "ql-indent-N" (where N is the indentation level) for both line indents and for nested lists. fn!richTextFieldWithTables uses the HTML standard style='margin-left: Npx' for line indents and nested list tags for nested lists (e.g. <ul><li>Bullet<ul><li>Nested Bullet</li></ul></li></ul>). This means that if you were using fn!richTextField and saved end-user formatted indentation or nested lists, fn!richTextFieldWithTables will not recognize these specific formats when rendering and will drop the indentation and nested lists.
  • Paragraphs: fn!richTextField relies on <div> tags to separate paragraphs, while fn!richTextFieldWithTables relies on <p> tags. This means that passing end-user formatting text from fn!richTextField to fn!richTextFieldWithTables will drop all paragraphs and carriage returns.
  • Font Color: fn!richTextField relies on <span> tags with a style attribute for font color (e.g. <span style='color: rgb(153, 51, 255);'>), while fn!richTextFieldWithTables relies on <font> tags with a color attribute (e.g. <font color='#9c00ff'>). This means that font colors will get dropped if you directly pass end-user formatting text from fn!richTextField to fn!richTextFieldWithTables.

If you'd like to migrate end-user formatting text to fn!richTextFieldWithTables, you can write an expression which updates the non-standard indentation attributes and div tags to be recognized by the new component. However this may be more involved for nested lists which will require a more complicated update than just find and replace.