MiCondition
The mEye UI framework provides a built-in feature for conditional rendering of UI elements directly within component JSON configurations. This eliminates the need for a dedicated MiCondition component in most cases. Conditional rendering is activated by including a "condition" block within any component's JSON definition.
Overview
Conditional rendering allows you to dynamically control which UI elements are displayed based on the evaluation of specified conditions. Key features include:
- Declarative Conditionals: Define conditional logic directly within your JSON UI configurations, making UI definitions more dynamic and readable.
- Data Binding in Conditions: Conditions can be based on values from the application's data model, enabling UI to react automatically to data changes.
- Nested Conditions: Supports nesting of conditions for complex conditional logic within UI structures.
- Variety of Operators: Offers a wide range of operators for defining conditions, including equality, inequality, comparisons, logical operators, list containment, null checks, and platform checks.
- Automatic Stream Updates: The framework automatically handles stream updates, ensuring that condition evaluations and UI rendering are re-evaluated and updated in real-time whenever relevant data changes.
- Applies to Any Component: Conditional logic can be applied to any UI component defined in JSON, not just a specific "condition" component.
Feature Key: "condition" block
JSON key: "condition": { ... } (used within any component's JSON definition).
The "condition" Block Structure
To implement conditional rendering for any component, you embed a "condition" block within its JSON definition. The "condition" block itself has the following structure:
{
"condition": [ "<operator>", <parameter1>, <parameter2>, ... ],
"true": <component_configuration_if_true>,
"false": <component_configuration_if_false>
}
This "condition" block is not a component itself. It is a structural element within other component definitions that triggers conditional rendering.
-
condition(List, Required): Specifies the condition to be evaluated. This is a JSON list defining a conditional expression to be resolved byConditionalsUtil.resolveCondition. The first element of the list is the operator (String), followed by one or more parameters (dynamic) that the operator will act upon. Parameters can be:- String: Interpreted as a data key. The value associated with this key in the application's data model will be retrieved and used as the parameter value.
- Any other JSON value: Used directly as the parameter value (e.g., numbers, booleans, lists, maps).
-
true(Map, Required): Defines the component configuration to be rendered if theconditionevaluates totrue. This should be a JSON map representing any valid Mia UI component configuration. -
false(Map, Optional): Defines the component configuration to be rendered if theconditionevaluates tofalse. If omitted, nothing will be rendered when the condition is false. This should also be a JSON map representing a component configuration.
Inherited Parameters:
Since the "condition" block is always used within another component's definition, it implicitly inherits all the standard layout parameters (padding, margin, alignment, color, width, height, etc.) of the component it is embedded within. There are no specific layout parameters directly for the "condition" block itself.
Condition Resolution
The condition list within the "condition" block is resolved using the ConditionalsUtil.resolveCondition method. The condition list follows this structure:
[ "<operator>", <parameter1>, <parameter2>, ... ]
Supported Operators:
The following operators are supported within the condition list:
| Operator | Description | Parameters | Example condition List |
|---|---|---|---|
equalsTo | Checks if parameter1 is equal to parameter2. | parameter1, parameter2 | ["equalsTo", "${DATA.VALUE_A}", "expectedValue"] |
notEqualsTo | Checks if parameter1 is not equal to parameter2. | parameter1, parameter2 | ["notEqualsTo", "${DATA.STATUS}", "completed"] |
smallerThan | Checks if parameter1 is numerically smaller than parameter2. | parameter1, parameter2 | ["smallerThan", "${DATA.COUNT}", 10] |
greaterThan | Checks if parameter1 is numerically greater than parameter2. | parameter1, parameter2 | ["greaterThan", "${DATA.SCORE}", 100] |
and | Performs a logical AND operation. Both parameter1 and parameter2 must be true for the condition to be true. | parameter1, parameter2 (must resolve to boolean) | ["and", "${DATA.IS_ADMIN}", "${DATA.IS_ACTIVE}"] |
or | Performs a logical OR operation. If either parameter1 or parameter2 is true, the condition is true. | parameter1, parameter2 (must resolve to boolean) | ["or", "${DATA.HAS_PERMISSION}", "${DATA.IS_GUEST}"] |
in | Checks if parameter1 is contained within the list parameter2. | parameter1, parameter2 (must be a List) | ["in", "${DATA.SELECTED_CATEGORY}", ["categoryA", "categoryB"]] |
isEmpty | Checks if parameter1 is a list and is empty. | parameter1 (must be a List) | ["isEmpty", "${DATA.ITEMS_LIST}"] |
isNotEmpty | Checks if parameter1 is a list and is not empty. | parameter1 (must be a List) | ["isNotEmpty", "${DATA.CART_ITEMS}"] |
isNull | Checks if parameter1 is null. | parameter1 | ["isNull", "${DATA.OPTIONAL_VALUE}"] |
isNotNull | Checks if parameter1 is not null. | parameter1 | ["isNotNull", "${DATA.USER_NAME}"] |
platform | Checks the current platform against parameter1. Returns true if the current platform matches parameter1. Supported platform values are: "web", "android", "ios", "macos", "windows", and "mobile" (for either iOS or Android). | parameter1 (String - platform name) | ["platform", "ios"] |
match | Acts as a switch/case statement. parameter1 is the value to match against cases defined as direct key-value pairs within the "condition" block itself (siblings to "condition", "true", "false"). The value associated with the matched case key is rendered. If no case matches, nothing is rendered (similar to a 'false' condition without a 'false' branch). | parameter1 (value to match) | See Example 2 below for usage. |
Note:
- Data Binding Context: When a parameter in the
conditionlist is a string starting with${, it is treated as a data binding key. The framework dynamically retrieves the current value associated with this key from the application's data model when evaluating the condition. - Dynamic Updates: The conditional rendering is reactive. Whenever the application's data stream emits a new event, any conditions that depend on the changed data are automatically re-evaluated, and the UI is updated accordingly.
- Nesting for Complex Logic: You can achieve complex conditional logic by nesting
"condition"blocks within thetrueorfalsebranches of other"condition"blocks. This allows you to create intricate decision trees within your UI configurations. matchOperator for Switch-Case: Thematchoperator provides a way to implement switch-case logic directly within your UI configuration. The value to be switched upon is provided as the first parameter in theconditionlist, and the cases are defined as key-value pairs within the"condition"block (siblings to "condition", "true", "false"). The key is the case value (as a string), and the value is the UI component configuration to render for that case.
Example JSON Configurations
Example 1: Simple Conditional Rendering of Text based on Boolean Value
{
"component": "column",
"children": [
{
"component": "text",
"text": "User Greeting:",
"fontSize": 18
},
{
"condition": {
"condition": ["equalsTo", "${USER.IS_LOGGED_IN}", true],
"true": {
"component": "text",
"text": "Welcome, User!",
"fontSize": 20
},
"false": {
"component": "text",
"text": "Please log in.",
"fontSize": 16
}
}
}
]
}
Explanation of Example 1:
- This configuration defines a
columncontaining two children. - The second child is a conditional block. It checks if the data value associated with the key
USER.IS_LOGGED_INis equal totrue. - If true, it renders a
textcomponent displaying "Welcome, User!". - If false, it renders a
textcomponent displaying "Please log in.".
Example 2: Using the match Operator for Switch-Case Logic to Render Different Headers
{
"component": "column",
"children": [
{
"condition": {
"condition": ["match", "${USER.ROLE}"],
"admin": {
"component": "header",
"label": "Admin Dashboard",
"level": 1
},
"editor": {
"component": "header",
"label": "Editor Panel",
"level": 1
},
"viewer": {
"component": "header",
"label": "Viewer Mode",
"level": 1
}
}
},
// ... other components in the column ...
]
}
Explanation of Example 2:
- This example uses a
"condition"block within acolumn's children. - It uses the
matchoperator to perform a switch-case based on the value ofUSER.ROLE. - Depending on the value of
USER.ROLE, it renders a differentheadercomponent with a corresponding label. - If
USER.ROLEdoesn't match any of the cases ("admin","editor","viewer"), nothing will be rendered from this conditional block within the column.
Example 3: Nested Conditions for Complex UI Logic within a Card
{
"component": "largeCard",
"header": "Item Details",
"body": {
"component": "column",
"children": [
{
"condition": {
"condition": ["isNotNull", "${ITEM.DATA}"],
"true": {
"component": "column",
"children": [
{
"component": "text",
"text": "Item Name: ${ITEM.DATA.NAME}",
"fontSize": 16
},
{
"condition": {
"condition": ["isNotEmpty", "${ITEM.DATA.ATTRIBUTES}"],
"true": {
"component": "listView",
"listKey": "${ITEM.DATA.ATTRIBUTES}",
"itemBuilder": {
"component": "text",
"text": "${ITEM.ATTRIBUTE.NAME}: ${ITEM.ATTRIBUTE.VALUE}"
}
},
"false": {
"component": "text",
"text": "No attributes available."
}
}
}
]
},
"false": {
"component": "text",
"text": "Loading item data..."
}
}
}
]
}
}
Explanation of Example 3:
- This example demonstrates nested
"condition"blocks within alargeCard'sbody. - The outer
"condition"checks ifITEM.DATAis not null. If null, it displays "Loading item data...". - If
ITEM.DATAis not null, it renders acolumncontaining item name and another nested"condition"block. - The inner
"condition"checks if the listITEM.DATA.ATTRIBUTESis not empty.- If not empty, it renders a
listViewto display attributes. - If empty, it renders "No attributes available.".
- If not empty, it renders a
Example 4: Conditional Button Rendering (Refactored Example)
{
"component": "row", // Example using condition within a row
"children": [
{
"component": "text",
"text": "Action Button:",
},
{
"condition": {
"condition": ["isNotNull", "${LIST}"],
"true": {
"component": "button",
"type": "filled",
"color": "accent",
"label": "Save",
"icon": "check",
"large": true,
"actionName": "save"
},
"false": {
"component": "button",
"type": "filled",
"color": "t3",
"label": "Save",
"icon": "check",
"large": true,
"actionName": null
}
}
}
]
}
Explanation of Example 4:
- This example shows the conditional button rendering you initially provided, but now correctly demonstrates the
"condition"block directly within thechildrenarray of arowcomponent, without any need for a wrappingmiConditioncomponent. - The button rendering logic remains the same: different button configurations are rendered based on whether
LISTdata is not null.