Developer Programs

Learn

Docs

Plugins

Components > Miscellaneous > Plugins
Use this feature to...
Embed one responsive UI application within another

Overview

Some applications visually integrate functionality from other applications into their own user interface. This plug-in approach involves two parts: the host application and the hosted application.

The host application provides the container of the user experience, including the header, the navigation, and the function view. It also provides a display block that contains the hosted application. The host application can either be a responsive web app or a WPF desktop app.

The hosted application displays simple content that can fit within a single display block. The hosted application is always a responsive web app for our purposes here.

If the host application is a web app, it uses an iframe to contain the hosted application. Otherwise if the host application is a native app, it uses an embedded browser component to contain the hosted application.

Hosted applications do not include any “chrome” elements like a header or navigation bar. Hosted apps also cannot include a display block or span multiple display blocks, because they reside within a display block at the host app level. This means that the hosted app must offer all of its functionality within one simple view. You can use container elements like tabs or group boxes to partition larger amounts of data. Another option is to break the hosted functionality into either separate smaller applets or multiple modes within one app, with the host application pointing to the appropriate applet or mode.

The host application provides the chrome — header, navigation, function view, display blocks — and one display block that contains the hosted application.
Host application
The hosted application provides its unique functionality, but does not display any chrome.
Hosted application
When implemented correctly, the user sees the host and hosted applications combined together as one, with no knowledge that two completely separate applications are involved.
Host and hosted applications together

Communication

Communication between the host and hosted applications is an important consideration. At the very least, the host application needs to provide the hosted application with information about the current context:

  • UI context: the current theme color and whether the host is data dense or data sparse. The hosted application must use this info to modify its appearance in order to visually fit well within the host application.
  • Business context: for example the current customer, current account, or any other business parameters that allow the hosted application to provide the correct functionality for where the user is in the overall application.

The simplest way for the host application to communicate initial context to the hosted application is with URL parameters. In the sample app shown in the screen shots below, the host application sends the current theme color via a “themeColor” parameter, and the data dense status via a “dense” parameter. The “appearance” parameter is omitted in this example, so it defaults to the Luxe appearance. The hosted application reads these URL parameters to understand which theme color to load and which CSS classes to apply to itself in order to visually mesh with its host application.

URL parameters are a one-time, one-way communication method, from the host application to the hosted application. Note that this approach does not allow for ongoing two-way communication. That kind of plumbing is beyond the scope of these UI patterns, but here are some options if ongoing communication is needed between the host and hosted applications:

  • If both apps are running within Xperience, you can use the Xperience message bus for real-time, two-way communication.
  • Otherwise, check with the EI&S team to ask about two-way communication for applications running outside of Xperience.

Apps that Need to Be both Hosted and Standalone

Some apps need to be hosted within another app in some cases but run standalone in other cases:

  • When hosted, the app does not display the standard header or navigation and does not use display blocks because it resides within a display block at the host app level.
  • When standalone, the app displays the standard header and navigation, and uses display blocks as needed.

View composition will be important for apps that run in both hosted and standalone mode. First, break the content displayed within each function view out to a new component. You can then either have one view that supports both hosted and standalone modes, including the function view and display block in standalone mode and omitting those in hosted mode. Or you could have two versions of the view, one with the function view and display blocks and another without it, both including the shared view content component.

A hosted app cannot include a display block or span multiple display blocks since it resides within a display block at the host app level. If a view uses multiple display blocks and needs to run in both hosted mode and standalone modes, you could create a container component that emits a display block in standalone mode but emits a group box in hosted mode and use that instead of a display block.


Development

While the high-level information in this section applies to both web and native host apps, the development details provided here are for web-based host apps.

Web component development

Host application

The host application designates a display block for the hosted application and includes an iframe within that display block. The iframe’s src should point to the hosted application’s URL. The host app should use CSS to set the iframe’s border to none and its width to 100%.

While it would be ideal if the hosted application could spread out and take all the height it needs within the host application, the hosted app is a completely separate web application from the host app, each with its own DOM. This means that the host app cannot know exactly how much height the hosted app will need at any given time. Because of this, the host app has to pick an arbitrary height in pixels for the hosted app and set that height on the hosted app’s iframe. The hosted app must display a vertical scrollbar whenever its height overflows the height of its iframe.

In the example below, the host app uses an iframe in a display block for the hosted app, binds the iframe’s src to a value in the component, and uses CSS to set the iframe’s border to none, its width to 100%, and its height to 400px. (There are some special steps needed to bind an iframe’s src for security reasons; those steps are not shown here.)

Host application
<style>
    .plug-in-container {
        border: none;
        width: 100%;
        height: 400px;
    }
</style>

. . .

<rui-display-block titleText="Deposits">

    <!-- Hosted app appears in iframe below -->
    <iframe [src]="hostedUrl" class="plug-in-container"></iframe>

</rui-display-block>

The host application must also communicate any contextual information needed by the hosted application. This includes (but is not limited to) the current theme color, the current appearance, whether the host is responsive or desktop, whether the host is data dense or not, and any business context such as the current customer or account.

Hosted Application

The hosted application must tailor its appearance to visually fit well with its host. The host app must communicate its current theme color, whether the host is responsive or desktop, and whether the host is data dense or not. The hosted app must then use that information to match the host app’s appearance.

The hosted application must do the following:

  • If the host application is a desktop app, then before loading a theme the hosted app must map theme colors that are not supported in responsive to appropriate equivalent theme colors in responsive.
    • Get the theme color from the parameter
    • Map the WPF Lemon theme colors to the responsive Tangerine theme. Responsive UI does not support the Lemon theme.
    • Map the WPF Institution theme colors to the responsive Steel theme colors. Responsive UI does not support the Institution theme.
  • Load the appropriate theme color based on the value passed in from the host app.

The example below shows the setup performed by a sample hosted application in its ngOnInit() method.

Hosted application
ngOnInit(): void {
    // Get theme color from parameter
    const lightDarkMode = this.getParameterByName('lightDarkMode', '');
    if (lightDarkMode === 'force-light') {
        document.documentElement.classList.add('light');
        document.documentElement.classList.remove('dark');
    } else if (lightDarkMode === 'force-dark') {
        document.documentElement.classList.add('dark');
        document.documentElement.classList.remove('light');
    } else {
        document.documentElement.classList.remove('dark');
        document.documentElement.classList.remove('light');
    }

    // Get theme color from parameter
    let themeColor = this.getParameterByName('themeColor', 'pacific');

    // Map non-supported theme colors to something similar
    if (themeColor.toLowerCase() === 'lemon') {
        themeColor = 'tangerine';
    } else if (themeColor.toLowerCase() === 'institution') {
        themeColor = 'steel';
    }

    ruiLoadTheme(themeColor, 'assets/rui-themes');

    this.transactions =
        [
            { date: new Date('11/29/2021'), location: 'Bank of America #332', transactionType: 'Withdrawal', amount: 600.00 },
            { date: new Date('12/2/2021'), location: 'Online', transactionType: 'Deposit', amount: 4334.17 },
            { date: new Date('12/31/2022'), location: 'Wells Fargo Mortgage', transactionType: 'Check', amount: 13652.11 },
            { date: new Date('1/19/2022'), location: 'Online', transactionType: 'Deposit', amount: 9641.95 },
            { date: new Date('2/16/2022'), location: 'Crest Cadillac', transactionType: 'Check', amount: 54112.62 }
        ];
    this.sortTransactions('neededBy');
}

private getParameterByName(name: string, defaultVal: string): string {
    const url = window.location.href;
    name = name.replace(/[\[\]]/g, "\\$&");
    const regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"), results = regex.exec(url);
    if (!results) {
        return defaultVal;
    }
    if (!results[2]) {
        return defaultVal;
    }
    return decodeURIComponent(results[2].replace(/\+/g, " "));
}

Angular wrapper development

Host Application

The host application designates a display block for the hosted application and includes an iframe within that display block. The iframe’s src should point to the hosted application’s URL. The host app should use CSS to set the iframe’s border to none and its width to 100%.

While it would be ideal if the hosted application could spread out and take all the height it needs within the host application, the hosted app is a completely separate web application from the host app, each with its own DOM. This means that the host app cannot know exactly how much height the hosted app will need at any given time. Because of this, the host app has to pick an arbitrary height in pixels for the hosted app and set that height on the hosted app’s iframe. The hosted app must display a vertical scrollbar whenever its height overflows the height of its iframe.

In the example below, the host app uses an iframe in a display block for the hosted app, binds the iframe’s src to a value in the component, and uses CSS to set the iframe’s border to none, its width to 100%, and its height to 400px. (There are some special steps needed to bind an iframe’s src for security reasons; those steps are not shown here.)

Host application
<style>
    .plug-in-container {
        border: none;
        width: 100%;
        height: 400px;
    }
</style>

. . .

<jha-display-block jhaTitle="Deposits">

    <!-- Hosted app appears in iframe below -->
    <iframe [src]="hostedUrl" class="plug-in-container"></iframe>

</jha-display-block>

The host application must also communicate any contextual information needed by the hosted application. This includes (but is not limited to) the current theme color, the current appearance, whether the host is responsive or desktop, whether the host is data dense or not, and any business context such as the current customer or account.

Hosted Application

The hosted application must tailor its appearance to visually fit well with its host. The host app must communicate its current theme color, whether the host is responsive or desktop, and whether the host is data dense or not. The hosted app must then use that information to match the host app’s appearance.

The hosted application must do the following:

  • Hard-code the jha-plug-in CSS class on the body tag in all cases. This ensures the proper colors and spacing are used for this special case of an application without chrome.
  • Dynamically add the jha-hosted-desktop CSS class to the body tag if the host app is a desktop app or add the jha-hosted-responsive CSS class to the body tag if the host app is a responsive web app. The themed colors for desktop are slightly different from those for responsive in some cases; use the appropriate CSS class here to get that right.
  • If the host application is a desktop app, then before loading a theme the hosted app must map theme colors that are not supported in responsive to appropriate equivalent theme colors in responsive.
    • Map the WPF Institution theme colors to the responsive Steel theme colors. The old Institution theme color set is not supported in responsive and the default look for the WPF Institution theme is grayscale colors like the Steel theme in responsive.
    • Map the WPF Contrast theme colors to the responsive Steel theme colors. Contrast is a true high-contrast theme color in responsive, but in WPF, Contrast looks more like the responsive Steel theme color set.
  • Load the appropriate theme color based on the value passed in from the host app.

The example below shows the setup performed by a sample hosted application in its ngOnInit() method.

Hosted application
ngOnInit(): void {

    // Get theme color from parameter
    this.themeColor = this.getParameterByName('themeColor', 'Pacific');

    // Get jha appearance from parameter
    this.appearance = this.getParameterByName('appearance', '');
    if (this.appearance.toLowerCase() === 'flat') {
        $('body').addClass('jha-flat');
    }

    // Map non-supported theme colors to something similar
    if (this.themeColor.toLowerCase() === 'terminal') {
        this.themeColor = 'Onyx';
    } else if (this.themeColor.toLowerCase() === 'institution') {
        this.themeColor = 'Steel';
    }

    // Get dense mode from parameter and add CSS class to body if appropriate
    this.isDense = this.getParameterByName('dense', '0') === '1';
    if (this.isDense) {
        $('body').addClass('jha-data-dense');
    }

    // Add appropriate CSS class to body to specify whether the hosting app is responsive or desktop
    if (this.getParameterByName('host', 'desktop').toLowerCase() === 'desktop') {
        $('body').addClass('jha-hosted-desktop');

        // Map desktop Contrast to Steel, since desktop Contrast
        // doesn't look at all like responsive Contrast
        if (this.themeColor.toLowerCase() === 'contrast') {
            this.themeColor = 'Steel';
        }
    } else {
        $('body').addClass('jha-hosted-responsive');
    }

    // Load appropriate theme
    this.themingService.LoadThemeColor(this.themeColor);
}

Design

There are no design elements specific to plugins.


Support options
Have questions on this topic?
Join the Responsive UI team in Microsoft Teams to connect with the community.
See something in this page that needs to change?
Send us feedback on this page.
Last updated Wed Nov 29 2023