Skip to main content

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 by ConditionalsUtil.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 the condition evaluates to true. This should be a JSON map representing any valid Mia UI component configuration.

  • false (Map, Optional): Defines the component configuration to be rendered if the condition evaluates to false. 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:

OperatorDescriptionParametersExample condition List
equalsToChecks if parameter1 is equal to parameter2.parameter1, parameter2["equalsTo", "${DATA.VALUE_A}", "expectedValue"]
notEqualsToChecks if parameter1 is not equal to parameter2.parameter1, parameter2["notEqualsTo", "${DATA.STATUS}", "completed"]
smallerThanChecks if parameter1 is numerically smaller than parameter2.parameter1, parameter2["smallerThan", "${DATA.COUNT}", 10]
greaterThanChecks if parameter1 is numerically greater than parameter2.parameter1, parameter2["greaterThan", "${DATA.SCORE}", 100]
andPerforms 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}"]
orPerforms 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}"]
inChecks if parameter1 is contained within the list parameter2.parameter1, parameter2 (must be a List)["in", "${DATA.SELECTED_CATEGORY}", ["categoryA", "categoryB"]]
isEmptyChecks if parameter1 is a list and is empty.parameter1 (must be a List)["isEmpty", "${DATA.ITEMS_LIST}"]
isNotEmptyChecks if parameter1 is a list and is not empty.parameter1 (must be a List)["isNotEmpty", "${DATA.CART_ITEMS}"]
isNullChecks if parameter1 is null.parameter1["isNull", "${DATA.OPTIONAL_VALUE}"]
isNotNullChecks if parameter1 is not null.parameter1["isNotNull", "${DATA.USER_NAME}"]
platformChecks 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"]
matchActs 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 condition list 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 the true or false branches of other "condition" blocks. This allows you to create intricate decision trees within your UI configurations.
  • match Operator for Switch-Case: The match operator 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 the condition list, 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 column containing two children.
  • The second child is a conditional block. It checks if the data value associated with the key USER.IS_LOGGED_IN is equal to true.
  • If true, it renders a text component displaying "Welcome, User!".
  • If false, it renders a text component 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 a column's children.
  • It uses the match operator to perform a switch-case based on the value of USER.ROLE.
  • Depending on the value of USER.ROLE, it renders a different header component with a corresponding label.
  • If USER.ROLE doesn'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 a largeCard's body.
  • The outer "condition" checks if ITEM.DATA is not null. If null, it displays "Loading item data...".
  • If ITEM.DATA is not null, it renders a column containing item name and another nested "condition" block.
  • The inner "condition" checks if the list ITEM.DATA.ATTRIBUTES is not empty.
    • If not empty, it renders a listView to display attributes.
    • If empty, it renders "No attributes available.".

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 the children array of a row component, without any need for a wrapping miCondition component.
  • The button rendering logic remains the same: different button configurations are rendered based on whether LIST data is not null.