Glue42 Enterprise is now io.Connect Desktop! The new documentation site for all interop.io products is located at docs.interop.io.

Data Sharing Between Apps

Context Components

The Glue42 Dash library offers two components for handling shared context objects - Context and Contexts.

The Context component binds to a specific context object and automatically subscribes for changes to it. You can set and update its value and also react to context updates. The id of the instantiated Context component is the name of the specific context object.

The Contexts component exposes an API for handling context objects by name - set and update their values, destroy contexts or set the values of nested properties using their paths in the context object.

To use the Glue42 Shared Contexts functionalities, instantiate the Context and/or Contexts components and pass an id to each component:

import dash
import dash_glue42

app = dash.Dash(__name__)

app.layout = dash_glue42.Glue42(id="glue42", children=[
    # Using the general API to set and update contexts.
    dash_glue42.Contexts(id="g42-shared-contexts"),

    # Subscribe to a specific context.
    dash_glue42.Context(id="app-styling")
])

See the Dash Shared Contexts example on GitHub.

Due to limitations of the Dash framework, the . and { characters can't be used in component IDs. This means that if you want to use the Context component to subscribe to a shared context whose name contains these characters, you can't use the id property, but must pass a contextName property specifying the name of the context to which to subscribe:

import dash
import dash_glue42

app = dash.Dash(__name__)

app.layout = dash_glue42.Glue42(id="glue42", children=[
    # Subscribing to a context whose name contains a `.` character.
    dash_glue42.Context(id="app-styling", contextName="App.Styling")
])

Updating Contexts

To update a shared context object, define an app callback. Pass the context component ID and its update property in the Output of the callback. For Input of the callback pass the ID and the property of the component that you want to trigger the context update.

The following examples demonstrate how to update the "app-styling" context using the Contexts and Context components. For the purpose of the examples, the Input component is a text input.

When using the Contexts component, it's required to pass the name of the context object you want to update:

# Define a callback that will trigger a context update
# when a specified property of a component changes.
@app.callback(
    Output("g42-shared-contexts", "update"),
    Input("background-color", "value"),
    prevent_initial_call=True
)
def update_app_styling_context(background_color):

    return {
        "name": "app-styling",
        "data": {
            "backgroundColor": background_color
        }
    }

When using the Context component to update a specific context object, return only the update data:

@app.callback(
    Output("app-styling", "update"),
    Input("background-color", "value"),
    prevent_initial_call=True
)
def update_app_styling_context(background_color):
    return { "backgroundColor": background_color }

Updating a context merges the existing properties of the context object with the properties of the update object. Only the specified context properties are updated, any other existing context properties will remain intact.

Updating Specific Properties

To update specific properties of a context object that aren't at top level, use the setPath or setPaths properties of the Contexts component.

Use setPath to update a single context object property. Return the name of the context to update, the path to the property to be updated and the new value for it. The path property of the returned object accepts a dot-separated string - e.g., "prop1.prop2". The data property of the returned object holds the new value for the updated property:

@app.callback(
    Output("g42-shared-contexts", "setPaths"),
    Input("background-color", "value"),
    prevent_initial_call=True
)
def update_app_styling_context(background_color):

    return {
        "name": "app-styling",
        "path": "colors.background",
        "data": background_color
    }

Use setPaths to update multiple context object properties. Return the name of the context to update, the paths and the new values for the updated properties. The paths property of the returned object is an array of objects holding the path and the new value for each updated property. The JavaScript equivalent of each object in the array is the PathValue object.

The following example demonstrates how to update the values of two context object properties simultaneously:

@app.callback(
    Output("g42-shared-contexts", "setPaths"),
    Input("background-color", "value"),
    Input("foreground-color", "value")
    prevent_initial_call=True
)
def update_app_styling_context(background_color, foreground_color):

    return {
        "name": "app-styling",
        "paths": [
            {
                "path": "colors.background",
                "value": background_color
            },
            {
                "path": "colors.foreground",
                "value": foreground_color
            }
        ]
    }

Replacing Contexts

To replace a shared context object, define an app callback. Pass the context component ID and its set property in the Output of the callback. For Input of the callback pass the ID and the property of the component that you want to trigger replacing the context.

The following examples demonstrates how to set an entirely new value for the "app-styling" context object using the Contexts and Context components.

When using the Contexts component, it is required to pass the name of the context object whose value you want to set:

# Define a callback that will trigger replacing the context
# when a specified property of a component changes.
@app.callback(
    Output("g42-shared-contexts", "set"),
    Input("default-styling-btn", "n_clicks"),
    prevent_initial_call=True
)
def set_default_app_styling(n_clicks):

    return {
        "name": "app-styling",
        "data": {
            "backgroundColor": "white",
            "color": "black"
        }
    }

When using the Context component to set the value of a specific context object, return only the data:

@app.callback(
    Output("app-styling", "set"),
    Input("default-styling-btn", "n_clicks"),
    prevent_initial_call=True
)
def set_default_app_styling(_):

    return {
        "backgroundColor": "white",
        "color": "black"
    }

Setting the value of a context removes and replaces all existing properties of the specified context object with the new ones.

Handling Context Updates

Use the Context component to handle context updates. Define an app callback handler and for Input pass the name of the context object and its context property which holds the current context value. The value of the context property is assigned by the framework and must not be altered by client code. Use the context object to extract the latest update from its data property, the delta between the latest and the previous states available in its delta property, or a string collection of the names of the removed context object properties available in its removed property. The context object also has an extraData property. The extraData object has an updaterId property holding the ID of the updating Interop instance, and an isMyUpdate Boolean property indicating whether the current Interop instance has updated the context. Use this information to avoid potential infinite loops if the subscribed app is also publishing updates to the same shared context. The handler will be triggered each time the context is updated. For Output of the callback pass the ID and the property of the component you want to update with the data from the context object.

The following example demonstrates how to update the style property of the "app-wrapper" component with data from the "app-styling" context object:

# Define a callback that will handle updates of the context object.
@app.callback(
    Output("app-wrapper", "style"),
    Input("app-styling", "context")
)
def app_styling_context_changed_handler(context):

    if context is not None:
        data = context.get("data", {})
        background_color = data.get("backgroundColor")
        font_color = data.get("color")

        return {
            "backgroundColor": background_color,
            "color": font_color
        }

Destroying Contexts

Use the Contexts component to destroy a context object. For Input of the callback pass the ID and the property of the component you want to trigger destroying the context. For Output, pass the ID of the Contexts component and its destroy property. Return an object with the name of the context you want to destroy:

# Define a callback that will destroy the context object.
@app.callback(
    Output("g42-shared-contexts", "destroy"),
    Input("destroy-context-btn", "n_clicks"),
    prevent_initial_call=True
)
def destroy_app_styling_context(n_clicks):
    return { "name": "app-styling" }