Client APIs – Mx8
Introduction
The main API the Mendix Platform provides to a pluggable widget client component is the props the component receives. These props resemble the structure of properties specified in the widget definition XML file (a structure described in Pluggable Widgets API). A property’s attribute type affects how the property will be represented to the client component. Simply, an attribute’s type defines what will it be. You can find the more details on property types and the interfaces that property value can adhere to in Pluggable Widget Property Types. To see examples of pluggable widgets in action, see How To Build Pluggable Widgets
The Mendix Platform also exposes a few JavaScript modules, specifically extra Mendix APIs as well as existing libraries, like React, that client components must share with the platform to function properly. For more information on exposed libraries, see the Exposed Libraries section below.
Bundling
Mendix does not provide you code as an npm package, which is the approach commonly used by JavaScript libraries. Instead, Mendix provides you modules available during execution. Hence, if you are using a module bundler like webpack, you should configure it to mark these modules as externals.
This process can be cumbersome, so it is recommended you use this tools package which contains the correctly-configured bundlers to work with pluggable widgets. If you follow best practices and use the Mendix Pluggable Widget Generator to scaffold your widget, then this package is added automatically.
Standard Properties
Alongside the props that correspond to the properties specified in widget definition XML file, the props listed below are always passed to a client component.
Name
In Mendix Studio Pro, every widget must have a name configured. The primary usage of a widget name is to make its component identifiable in the client so that it can be targeted using Selenium or Appium test automation. In web apps, the Mendix Platform automatically adds the class mx-name-{widgetName}
to a widget so that no extra action from a component developer is required. Unfortunately, this solution is not possible for native mobile apps. For native mobile apps a component developer must manually pass a given string
name
prop to an underlying React Native testID.
Class
A user can specify multiple classes for every widget. They can do this either directly by configuring a class property in Studio Pro, or by using design properties. In web apps, the Mendix Platform creates a CSS class string from the configuration and passes it as a string
class
prop to every client component. Unfortunately, React Native does not have similar support for classes. Therefore in native mobile apps a component will not receive class
prop, but a style
prop instead.
Style
A user can specify a custom CSS for every widget on a web page by using the style property. This styling is passed to a client component through an optional style
prop of the type CSSProperties
.
On native pages, the meaning of a style
prop is very different. First of all, a user cannot specify the aforementioned inline styles for widgets on a native page. So a style
prop is used to pass styles computed based on configured classes. A client component will receive an array with a single style object with all applicable styles combined.
TabIndex
If a widget uses a TabIndex prop system property, then it will receive a configured Tab index
through a number
tabIndex
property, except in the case when a configured tab index is on its default value of 0. Currently, tabIndex
is not passed to widgets used on native pages.
Property Values
ActionValue
ActionValue is used to represent actions, like the On click property of an action button. For any action except Do nothing, your component will receive a value adhering to the following interface. For Do nothing it will receive undefined
. The ActionValue
prop appears like this:
export interface ActionValue {
readonly canExecute: boolean;
readonly isExecuting: boolean;
execute(): void;
}
The flag canExecute
indicates if an action can be run under the current conditions. This helps you prevent executing actions that are not allowed by the app’s security settings. User roles can be set in the microflows and nanoflows, allowing users to call them. For more information on user roles and security, see the Module Security Reference Guide. You can also employ this flag when using a Call microflow action triggering a microflow with a parameter. Such an action cannot be run until a parameter object is available, for example when a parent Data view has finished loading. An attempt to execute
an action that cannot be run will have no effect except generating a debug-level warning message.
The flag isExecuting
indicates whether an action is currently running. A long-running action can take seconds to complete. Your component might use this information to render an inline loading indicator which lets users track loading progress. Often it is not desirable to allow a user to trigger multiple actions in parallel. Therefore, a component (maybe based on a configuration) can decide to skip triggering an action while a previous execution is still in progress.
Note that isExecuting
indicates only whether the current action is running. It does not indicate whether a target nanoflow, microflow, or object operation is running due to another action.
The method execute
triggers the action. It returns nothing and does not guarantee that the action will be started synchronously. But when the action does start, the component will receive a new prop with the isExecuting
flag set.
DynamicValue
DynamicValue is used to represent values that can change over time and is used by many property types. It is defined as follows:
export type DynamicValue<X> =
| { readonly status: ValueStatus.Available; readonly value: X }
| { readonly status: ValueStatus.Unavailable; readonly value: undefined }
| { readonly status: ValueStatus.Loading; readonly value: X | undefined };
export const enum ValueStatus {
Loading = "loading",
Unavailable = "unavailable",
Available = "available"
}
A component will receive a DynamicValue<X>
where type X
depends on a property configuration. For example, for the TextTemplate property it will be DynamicValue<string>
, but for the expression property X
will depend on a configured returnType
.
Though the type definition above looks complex, it is fairly simply to use because a component can always read DynamicValue.value
. This field either contains an actual value, such as an interpolated string
in the case of a Text template, or the last known correct value if the value is being recomputed, such as when a parent Data view reloads its Data source. In other cases the value is set as undefined
.
DynamicValue.status
provides a component with additional information about the state of a dynamic value, as well as if the component should handle them differently. This is done using a discriminated union that covers the following situations:
- When
status
isValueStatus.Available
, then the dynamic value has sufficient information to be computed, and the result is exposed invalue
. - When
status
isValueStatus.Unavailable
, then the dynamic value does not have such information such as when a parent Data view’s Data source has returned nothing. Thevalue
is then alwaysundefined
. - When
status
isValueStatus.Loading
, then the dynamic value is awaiting for the required information to arrive. This happens when a parent Data view is either waiting for its object to load or is reloading it due to a refresh in client.- In case a dynamic value was previously in a
ValueStatus.Available
state, then the previousvalue
is still returned. This is done so that a component can keep showing the previous value if it doesn’t need to handleLoading
explicitly. This prevents flickering: a state when a displayed value rapidly changes between loading and not loading several times. - In other cases, the
value
isundefined
. This is a common situation while a page is still being loaded.
- In case a dynamic value was previously in a
EditableValue
EditableValue is used to represent values that can be changed by a pluggable widget client component and is passed only to attribute properties. It is defined as follows:
export interface EditableValue<T extends AttributeValue> {
readonly status: ValueStatus;
readonly readOnly: boolean;
readonly value: T | undefined;
setValue(value: T | undefined): void;
readonly validation: string | undefined;
setValidator(validator?: (value: T | undefined) => string | undefined): void;
readonly displayValue: string;
setTextValue(value: string): void;
readonly formatter: ValueFormatter<T>;
setFormatter(formatter: ValueFormatter<T> | undefined): void;
readonly universe?: T[];
}
A component will receive EditableValue<X>
where X
depends on the configured attributeType
.
status
is similar to one exposed for DynamicValue
. It indicates if the value’s loading has finished and if loading was successful. Similarly to DynamicValue
, EditableValue
keeps returning the previous value
when status
changes from Available
to Loading
to help a widget avoid flickering.
The flag readOnly
indicates whether a value can actually be edited. It will be false, for example, when a widget is placed inside a Data view that is not editable, or when a selected attribute is not editable due to access rules. The readOnly
flag is always false when a status
is not ValueStatus.Available
. Any attempt to edit a value set to read-only will have no affect and incur a debug-level warning message.
The value can be read from the value
field and modified using setValue
function. Note that setValue
returns nothing and does not guarantee that the value is changed synchronously. But when a change is propagated, a component receives a new prop reflecting the change.
When setting a value, a new value might not satisfy certain validation rules — for example a value might be bigger that the underlying attribute allows. In this case, your change will affect only value
and displayValue
received through a prop. Your change will not be propagated to an object’s attribute and will not be visible outside of your component. The component will also receive a validation error text through the validation
field of EditableValue
.
It is possible for a component to extend the defined set of validation rules. A new validator — a function that checks a passed value and returns a validation message string if any — can be provided through the setValidator
function. A component can have only a single custom validator. The Mendix Platform ensures that custom validators are run whenever necessary, for example when a page is being saved by an end-user. It is best practice to call setValidator
early in a component’s lifecycle — specifically in the componentDidMount function.
In practice, many client components present values as nicely formatted strings which take locale-specific settings into account. To facilitate such cases EditableValue
exposes a field displayValue
formatted version of value
, and a method setTextValue
— a version of setValue
that takes care of parsing. setTextValue
also validates that a passed value can be parsed and assigns the target attribute’s type. Similarly to setValue
, a change to an invalid value will not be propagated further that the prop itself, but a validation
is reported. Note that if a value cannot be parsed, the prop will contain only a displayValue
string and value
will become undefined.
There is a way to use more the convenient displayValue
and setTextValue
while retaining control over the format. A component can use a setFormatter
method passing a formatter object: an object with format
and parse
methods. The Mendix Platform provides a convenient way of creating such objects for simple cases. An existing formatter exposed using a EditableValue.formatter
field can be modified using its withConfig
method. For complex cases formatters still can be created manually. A formatter can be reset back to default settings by calling setFormatter(undefined)
.
The optional field universe
is used to indicate the set of all possible values that can be passed to a setValue
if a set is limited. Currently, universe
is provided only when the edited attribute is of the Boolean or enumeration types.
IconValue
DynamicValue<IconValue>
is used to represent icons: small pictograms in the Mendix Platform. Those can be static or dynamic file- or font-based images. An icon can only be configured through an icon property. IconValue
is defined as follows:
interface GlyphIcon {
readonly type: "glyph";
readonly iconClass: string;
}
interface WebImageIcon {
readonly type: "image";
readonly iconUrl: string;
}
interface NativeImageIcon {
readonly type: "image";
readonly iconUrl: Readonly<ImageURISource>;
}
export type WebIcon = GlyphIcon | WebImageIcon | undefined;
export type NativeIcon = GlyphIcon | NativeImageIcon | undefined;
export type IconValue = WebIcon | NativeIcon;
In practice, WebIcon
and NativeIcon
are usually passed to a Icon
component provided by Mendix, since this provides a convenient way of handling all types of icons at once. For more information on Icon
, see the Icon section below.
ImageValue
DynamicValue<ImageValue>
is used to represent static or dynamic images. An image can be configured only through an image property. ImageValue
is defined as follows:
export interface WebImage {
readonly uri: string;
readonly name: string;
readonly altText?: string;
}
export type NativeImage = Readonly<ImageURISource & { name?: string; } | string | number>;
export type ImageValue = WebImage | NativeImage;
NativeImage
can be passed to a mendix/components/native/Image
component provided by Mendix for native widgets. WebImage
can be passed to react-dom’s img
component.
FileValue
DynamicValue<FileValue>
is used to represent files. A file can be configured only through a file property. FileValue
is defined as follows:
export interface FileValue {
readonly uri: string;
readonly name: string;
}
ListValue
ListValue
is used to represent a list of objects for the datasource property.
export interface ObjectItem {
id: GUID;
}
export interface ListValue {
status: ValueStatus;
offset: number;
limit: number;
setOffset(offset: number): void;
setLimit(limit: Option<number>): void;
items?: ObjectItem[];
hasMoreItems?: boolean;
totalCount?: number;
}
When a datasource
property with isList="true"
is configured for a widget, the client component gets a list of objects represented as a ListValue
. This type allows detailed access to a data source, and enables control over the limit and offset of items represented in the list.
However it is not possible to access domain data directly from ListValue
, as every object is represented only by GUID in the items
array. Instead, a list of items may be used in combination with other properties, for example with a property of type attribute
, action
or widgets
.
ListActionValue
ListActionValue
represents actions that may be applied to items from ListValue
. The ListActionValue
is a function and its definition is as follows:
export type ListActionValue = (item: ObjectItem) => ActionValue;
In order to call an action on a particular item of a ListValue
first an instance of ActionValue
should be obtained by calling ListActionValue
with the item. See an example below.
Assuming widget properties are confgured as follows:
interface MyListWidgetsProps {
myDataSource: ListValue;
myListAction: ListActionValue;
}
The following code sample shows how to call myListAction
on the first element from the myDataSource
.
const actionOnFirstItem = this.props.myListAction(this.props.myDataSource.item[0]);
actionOnFirstItem.execute();
In this code sample, checks of status myDataSource
and availability of items are omitted for simplicity. See ActionValue section for more information about usage of ActionValue
.
ListAttributeValue
ListAttributeValue
represents an attribute property that is linked to a data source.
This allows the client component to access attribute values on individual items from a ListValue
. ListAttributeValue
is a function and its definition is as follows:
export type ListAttributeValue<T extends AttributeValue> = (item: ObjectItem) => EditableValue<T>;
The type <T>
depends on the allowed value types as configured for the attribute property.
ListAttributeValue
. EditableValue
s returned by ListAttributeValue
are always readonly.
In order to work with the attribute value of a particular item of a ListValue
first an instance of EditableValue
should be obtained by calling ListAttributeValue
with the item. See an example below.
Assuming widget properties are configured as follows (with an attribute of type string
):
interface MyListWidgetsProps {
myDataSource: ListValue;
myAttributeOnDatasource: ListAttributeValue<string>;
}
The following code sample shows how to get an EditableValue
that represents a read-only value of an attribute of the first element from the myDataSource
.
const attributeValue = this.props.myAttributeOnDatasource(this.props.myDataSource.items[0]);
Note: in this code sample checks of status of myDataSource
and availability of items are omitted for simplicity. See EditableValue section for more information about usage of EditableValue
.
ListWidgetValue
ListWidgetValue
represents a widget property that is linked to a data source.
This allows the client component to render child widgets with items from a ListValue
.
ListWidgetValue
is a function and its definition is as follows:
export type ListWidgetValue = (item: ObjectItem) => ReactNode;
For clarity, consider the following example using ListValue
together with the widgets
property type. When the widgets
property named myWidgets
is configured to be tied to a datasource
named myDataSource
, the client component props appear as follows:
interface MyListWidgetsProps {
myDataSource: ListValue;
myWidgets: (i: ObjectItem) => ReactNode;
}
Because of the above configurations, the client component may render every instance of widgets with a specific item from the list like this:
this.props.myDataSource.items.map(i => this.props.myWidgets(i));
ListExpressionValue
ListExpressionValue
represents an expression property or text template property that is linked to a data source. This allows the client component to access expression or text template values for individual items from a ListValue
. ListExpressionValue
is a function and its definition is as follows:
export type ListExpressionValue<T extends AttributeValue> = (item: ObjectItem) => DynamicValue<T>;
The type <T>
depends on the return type as configured for the expression property. For a text template property, this type is always string
.
In order to work with the expression or text template value of a particular item of a ListValue
, first an instance of DynamicValue
should be obtained by calling ListExpressionValue
with the item. See an example below.
Assuming widget properties are configured as follows (with an expression of type boolean
):
interface MyListWidgetsProps {
myDataSource: ListValue;
myExpressionOnDatasource: ListExpressionValue<boolean>;
myTextTemplateOnDatasource: ListExpressionValue<string>;
}
The following code sample shows how to get a DynamicValue
that represents the value of an expression for the first element from the myDataSource
.
const expressionValue = this.props.myDataSource.myExpressionOnDatasource(this.props.myDataSource.item[0]);
Exposed Modules
Icon
Mendix Platform exposes two versions of an Icon
react component: mendix/components/web/Icon
and mendix/components/native/Icon
. Both components are useful helpers to render WebIcon
and NativeIcon
values respectively. They should be passed through an icon
prop. The native Icon
component additionally accepts color
(string
) and size
(number
) props.
Exposed Libraries
React and React Native
Mendix Platform re-export react, react-dom, and react-native packages to pluggable widgets. React is available to all components. React-dom is available only to components running in web or hybrid mobile apps. React-native is available only to components running in native mobile apps.
Mendix provides you with React version 16.9.x (in npm terms ~16.9.0
). Patch versions might change from one minor release of Mendix to another. Mendix will always provide a matching version of react-dom.
For react-native Mendix exposes a single version: 0.61.5. Mendix also includes the following libraries:
Big.js
The Mendix Platform uses big.js to represent and operate on numbers. Mendix 8.0 re-exports version 5.2.
Read More
- Pluggable Widgets API Documentation
- Pluggable Widget Property Types Documentation (Mendix 8)
- How to Build Pluggable Widgets