Data Sharing
Context Components
The io.Connect 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 io.Connect 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="io-connect", children=[
# Using the general API to set and update contexts.
dash_glue42.Contexts(id="io-connect-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="io-connect", 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("io-connect-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("io-connect-shared-contexts", "setPath"),
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("io-connect-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("io-connect-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("io-connect-shared-contexts", "destroy"),
Input("destroy-context-btn", "n_clicks"),
prevent_initial_call=True
)
def destroy_app_styling_context(n_clicks):
return { "name": "app-styling" }