Data Sharing Between Apps

Overview

The io.Connect Channels are globally accessed named contexts that allow users to dynamically group apps via the UI, instructing them to work over the same shared data object. Your apps can join, leave, subscribe and publish to Channels programmatically. Channels can also be represented visually via a Channel Selector app which allows users to join, leave or switch between Channels manually from the UI. Apps on the same Channel share a context data object which they can monitor and update.

The @interopio/widget library enables you to add the io.Connect widget to your apps. The widget contains a fully functional Channel Selector UI which enables users to control Channels manually.

io.Connect Browser supports directional Channels which allow for finer user control over whether an app should publish or subscribe to a Channel.

Channels are based on Shared Contexts. A context object may contain various types of data such as ids, displayName, and more:

{
    "contact": {
        "ids": [
        {
            "systemName": "sfId",
            "nativeId": "0031r00002IukOxAAJ"
        },
        {
            "systemName": "rest.id",
            "nativeId": "0e23375b-dd4f-456a-b034-98ee879f0eff"
        }
        ],
        "displayName": "Nola Rios",
        "name": {
            "lastName": "Rios",
            "firstName": "Nola",
            "otherNames": null,
            "honorific": "Ms.",
            "postNominalLetters": null
        }
    }
}

Different apps on the same Channel may use different parts of the data:

  • A "Client List" app may update the context object fields with data for the selected user.
  • A "Client Portfolio" app may use the ids property to load the portfolio of the client selected by the user in the "Client List" app.

The Channels API is accessible via the io.channels object.

The Live Examples section demonstrates using the Channels API.

Channel Selector

The Channel Selector enables users to manually assign Channels to their apps and also control the flow of data when using directional Channels. io.Connect Browser supports different types of Channel Selectors with standard and directional Channels. Standard Channels allow apps to publish and subscribe for Channel data unrestrictedly. Directional Channels offer finer user control - besides selecting a Channel for the app, the user can restrict the app from publishing or subscribing to that Channel depending on the desired direction of the data flow.

io.Connect Browser offers out-of-the-box implementations of a Channel Selector accessible via:

  • the io.Connect widget which can be enabled and configured in the Main app and per Browser Client app. The widget supports single, directional single, and multiple Channels;
  • the Channel Selector icon displayed in the tabs of Workspace windows which can be enabled per app via the app definition. The Workspace window Channel Selector supports only single Channels;

Types

Single

The single Channel Selector is the default one and it allows users to select a single Channel for the window. The window will be able to subscribe and publish to that Channel unrestrictedly. Single Channels are supported by the io.Connect widget and the Workspace window Channel Selector.

Channel Selector Single

Directional Single

The directional single Channel Selector allows users to select a single Channel for the window, but also enables them to instruct the window only to publish or subscribe to the selected Channel. Directional single Channels are supported only by the io.Connect widget.

Channel Selector Directional Single

Multi

Available since io.Connect Browser 3.5

The multi Channel Selector allows users to select multiple Channels for the window. The window will be able to subscribe and publish to the selected Channels simultaneously and unrestrictedly. Multiple Channels are supported only by the io.Connect widget:

Widget Multi Channels

Widget

Available since io.Connect Browser 3.3

The io.Connect widget supports single, directional single, and multiple Channels. The widget enables Browser Clients opened as floating windows or ejected from a Workspace to provide a Channel Selector UI to the user:

Widget Channel Selector

Workspace Windows

The Workspace window Channel Selector supports only single Channels and enables users to manually select a Channel for the window:

Workspace Window Channel Selector

Available since io.Connect Browser 3.5

The Workspace window Channel Selector can be enabled per Browser Client app via the channelSelector property of the details object in the app definition:

import IOBrowserPlatform from "@interopio/browser-platform";

const config = {
    licenseKey: "my-license-key",
    applications: {
        local: [
            {
                name: "my-app",
                type: "window",
                title: "My App",
                details: {
                    url: "https://my-domain.com/my-app",
                    channelSelector: {
                        enabled: true
                    }
                }
            }
        ]
    }
};

const { io } = await IOBrowserPlatform(config);

The channelSelector object has the following properties:

Property Type Description
enabled boolean Required. If true, the Channel Selector will be enabled for the window. Defaults to false.

Defining Channels

The Channels are enabled by default for all apps in an io.Connect Browser project. If you decide to migrate your app to io.Connect Desktop, no code change will be necessary as the Channels will be automatically enabled for your app there as well.

Use the channels property of the configuration object when initializing the @interopio/browser-platform library in the Main app to define the Channels that will be available for your project:

import IOBrowserPlatform from "@interopio/browser-platform";

const config = {
    licenseKey: "my-license-key",
    channels: {
        // Channel definitions.
        definitions: [
            {
                name: "Red",
                meta: {
                    color: "red"
                },
                data: { io: 42 }
            },
            {
                name: "Green",
                meta: {
                    color: "#008000"
                }
            }
        ]
    }
};

const { io } = await IOBrowserPlatform(config);

The only required properties in a Channel definition object are name and color. The color property expects an HTML color name or a hex value. You can add any number of additional custom properties to the meta object. The data property holds context data specific to the Channel.

Channel Mode

Available since io.Connect Browser 3.5

io.Connect Browser provides experimental support for working with multiple Channels simultaneously.

⚠️ Note that this functionality is still experimental and you should take into consideration the following:

The Channel mode is set by the io.Connect framework based on the provided configuration for initializing the Main app. To set the Channel mode, use the mode property of the channels top-level key:

import IOBrowserPlatform from "@interopio/browser-platform";

const config = {
    licenseKey: "my-license-key",
    channels: {
        definitions: [
            // Channel definitions.
        ],
        // Enabling multi Channel mode.
        mode: "multi"
    }
};

const { io } = await IOBrowserPlatform(config);

To retrieve the current Channel mode (single or multi), use the mode property:

const channelMode = io.channels.mode;

if (channelMode === "single") {
    // Handle Channel operations in single Channel mode.
} else if (channelMode === "multi") {
    // Handle Channel operations in multi Channel mode.
};

Multiple Channels

Available since io.Connect Browser 3.5

⚠️ Note that the multi Channel support is still an experimental feature of io.Connect Browser. For details on how to enable using multiple Channels and the considerations you should take into account, see the Channel Mode section.

⚠️ Note that the my(), getMy(), and onChanged() methods for working with single Channels aren't deprecated, but it's highly recommended to use the myChannels(), getMyChannels() and onChannelsChanged() methods instead, which support working both with single and multiple Channels.

Current Channels

To retrieve the list of names of the Channels to which your window is currently joined, use the myChannels() method:

const channelNames = await io.channels.myChannels();

Retrieving Channel Contexts

To retrieve a list of the contexts of all Channels to which the window is currently joined, use the getMyChannels() method:

const channelContexts = await io.channels.getMyChannels();

Current Channel

⚠️ Note that it's highly recommended to use the myChannels() method instead, which supports working both with single and multiple Channels.

To retrieve the name of the Channel to which your window is currently joined, use the my() method:

const myChannel = io.channels.my();

All Channels

To retrieve a list of all Channel names, use the all() method:

const channelNames = await io.channels.all();

Add & Remove Channels

Available since io.Connect Browser 3.3

You can add or remove Channels at runtime. New dynamically added Channels won't be persisted after restart of io.Connect Browser, unless they are recreated. A Channel that has been defined by the platform and is dynamically removed will be restored on restart of io.Connect Browser.

To add a Channel dynamically, use the add() method and pass a ChannelContext object as an argument:

const channelContext = {
    name: "Black",
    meta: { color: "black" },
    data: { io: 42 }
};

// Adding a new Channel.
const newChannelContext = await io.channels.add(channelContext);

To remove a Channel dynamically, use the remove() method and pass the name of the Channel to remove:

// Removing a Channel.
await io.channels.remove("Black");

Join & Leave Channels

To join a Channel, use the join() method and specify the name of the Channel to join:

await io.channels.join("Red");

To leave the Channel to which your window is currently joined, use the leave() method. If in multi Channel mode, this will remove your window from all currently joined Channels:

await io.channels.leave();

Available since io.Connect Browser 3.5

The leave() method accepts as an argument an object with optional windowId and channel properties which you can use to specify which window instance from which Channel to remove. If you provide only the window ID, the specified window will be removed from the current Channel, or from all currently joined Channels if in multi Channel mode. If you provide only the Channel name, the current window will be removed from the specified Channel:

const options = {
    windowId: win.id,
    channel: "Red"
};

await io.channels.leave(options);

Retrieving Channel Context

⚠️ Note that it's highly recommended to use the getMyChannels() method instead, which supports working both with single and multiple Channels.

To retrieve the context of the current Channel, use the getMy() method:

const channelContext = await io.channels.getMy();

To retrieve the context of a specific Channel, use the get() method which accepts a Channel name as a required argument:

const channelContext = await io.channels.get("Green");

To retrieve a list of the contexts of all Channels, use the list() method:

const channelContexts = await io.channels.list();

For details on how to retrieve FDC3 User Channels contexts in a non-FDC3 interop-enabled app, see the Getting Started > FDC3 Compliance > Channels section.

Subscribing for Channel Updates

To track the data in the current Channel, use the subscribe() method:

const handler = (data) => {
    // The callback will be invoked each time the data is updated.
    console.log(data);
};

// Subscribe for updates from the Channel to which your window is currently joined.
io.channels.subscribe(handler);

The callback receives the data from the Channel and information about the current Channel.

The callback will be invoked in three cases:

  • the data property of the Channel you are currently on is updated;
  • the user has switched the Channel and you are receiving a snapshot of the new Channel data;
  • your app isn't joined to a Channel anymore (e.g., the user has deselected the current Channel);

To subscribe for updates from a specific Channel, use the subscribeFor() method:

const channelName = "Green";
const handler = (data, channelInfo) => {
    // The callback will be invoked each time the data is updated.
    console.log(data);
};

await io.channels.subscribeFor(channelName, handler);

The subscribeFor() method accepts a Channel name as a first argument and a callback to handle Channel data updates.

Use the unsubscribe function returned by subscribe() and subscribeFor() to stop tracking updates of the Channel data:

const unsubscribe = await io.channels.subscribeFor(channelName, handler);

unsubscribe();

The handlers passed to the subscribe() and subscribeFor() methods also accept the Channel context and the updating Interop Instance peer ID as second and third arguments. The ChannelContext object contains the name of the Channel, the Channel meta data, and the Channel data. The updating Interop instance peer ID can be used to identify the app instance updating the Channel:

const handler = (data, channelContext, updaterID) => {
    // Check the current Interop instance peer ID against the updating instance ID.
    const isUpdatedByMe = io.interop.instance.peerId === updaterID;

    if(!isUpdatedByMe) {
        // Another app has published in the Channel.
        console.log(`App "${updaterID}" has published "${JSON.stringify(data)}" in Channel "${channelContext.name}".`);
    };
};

io.channels.subscribe(handler);

For details on how to subscribe to FDC3 User Channels contexts in a non-FDC3 interop-enabled app, see the Getting Started > FDC3 Compliance > Channels section.

Publishing Data

To update the context of the Channel, use the publish() method. It accepts the data to publish as a first required argument, and an optional Channel name as a second argument specifying which Channel context to update. If you don't specify a Channel name, the current Channel will be updated.

Updating the current Channel:

const data = { io: 42 };

await io.channels.publish(data);

Updating a specific Channel:

const data = { io: 42 };
const channelName = "Green";

await io.channels.publish(data, channelName);

Channels may contain multiple data structures. When updating the Channel context, only the specified fields will be updated, leaving all other fields of the context unchanged.

The publish() method will throw an exception if your window isn't joined to a Channel but tries to publish data.

For details on how to publish FDC3 User Channels contexts in a non-FDC3 interop-enabled app, see the Getting Started > FDC3 Compliance > Channels section.

Channel Restrictions

Available since io.Connect Browser 3.3

To apply restrictions to windows for publishing or subscribing to Channels, use the restrict() method and provide a ChannelRestrictions object as a required argument. The following example demonstrates how to prevent the current window from publishing to the "Red" Channel:

// Restricting the current window from publishing to a Channel.
const restrictions = {
    name: "Red",
    read: true,
    write: false
};

await io.channels.restrict(restrictions);

To apply restrictions to another window for publishing or subscribing to a Channel, provide the window ID in the ChannelRestrictions object:

// Restricting a specific window from publishing to a Channel.
const restrictions = {
    name: "Red",
    read: true,
    write: false,
    // ID of the window you want to restrict.
    windowId: win.id
};

await io.channels.restrict(restrictions);

To apply restrictions to windows for publishing or subscribing to all Channels, use the restrictAll() method and provide a RestrictionsConfig object as a required argument. The following example demonstrates how to prevent the current window from publishing to all Channels:

// Restricting the current window from publishing to all Channels.
const restrictions = {
    read: true,
    write: false
};

await io.channels.restrictAll(restrictions);

To apply restrictions to another window for publishing or subscribing to all Channels, provide the window ID in the RestrictionsConfig object:

// Restricting a specific window from publishing to all Channels.
const restrictions = {
    read: true,
    write: false,
    // ID of the window you want to restrict.
    windowId: win.id
};

await io.channels.restrictAll(restrictions);

To retrieve the applied Channel restrictions for the current window, use the getRestrictions() method. If you want to get the applied Channel restrictions for a specific window, pass a window ID as an optional argument. The method resolves with a Restrictions object with a channels property holding a list of ChannelRestrictions objects:

// Retrieving the Channel restrictions for the current window.
const { channels } = await io.channels.getRestrictions();

channels.forEach(console.log);

Events

The Channels API provides methods for reacting to various Channel events. Use the returned unsubscribe function to stop receiving notifications about the respective event.

Channel Changed

⚠️ Note that it's highly recommended to use the onChannelsChanged() method instead, which supports working both with single and multiple Channels.

To get notified when the current Channel of your window is changed, use the onChanged() method:

const handler = (newChannel) => {
    if (newChannel) {
        // Handle the case where you have switched to another Channel.
        console.log(newChannel);
    } else {
        // Handle the case where your window isn't joined to any Channel
        // (e.g., the user has deselected the current Channel).
        console.log("No Channel selected.")
    };
};

io.channels.onChanged(handler);

Available since io.Connect Browser 3.5

To get notified when the current Channels of your windows are changed, use the onChannelsChanged() method. This method can be used both in single and in multi Channel mode:

// The handler receives as an argument a list of all currently joined Channels.
const handler = (channelNames) => {
    channelNames.forEach(console.log);
};

const unsubscribe = io.channels.onChannelsChanged(handler);

Live Examples

Discover and Navigate

The app below demonstrates how to navigate through the available Channels using the join() and leave() methods of the Channels API. An app can be part of only one Channel at a time. The example app also demonstrates how to get the context (name, meta, data) of any Channel using the get() method. Discovering the available Channels is achieved using the all() method.

The background color of the example app reflects the color of the current Channel. Click on the "Get" button to log the context data of the selected Channel.

Publish and Subscribe

Once multiple apps are on the same Channel, they can communicate by publishing and subscribing data to the Channel. This is achieved through the shared context data object that the apps monitor using the subscribe() method of the Channels API and/or update using the publish() method. The callback provided to subscribe() is invoked when the context of the Channel that the app is currently on has been updated.

When the two apps below are on the same Channel, App B can publish data that is received and logged by App A if it has subscribed for updates of the current Channel. If the apps aren't on the same Channel, or if App A hasn't subscribed for updates, the apps won't exchange any data.

Channel Selector UI

To allow the users of your io.Connect Browser app to use the available Channels, you will need to provide them with some sort of UI. Below are examples of Channel Selector widgets developed using the Channels API and some of the most popular libraries and frameworks.

⚠️ Note that these widgets are only examples. Feel free to use them as they are or as a reference to create your own Channel Selector. io.Connect Desktop ships with a fully functioning Channel Selector that all apps with enabled Channels can use.

JavaScript

The example below uses a custom jQuery Selectmenu widget:

Reference

For a complete list of the available Channels API methods and properties, see the Channels API Reference Documentation.