Using the Ignite UI for Web Components Dock Manager in Blazor

Brian Lagunas / Tuesday, September 15, 2020

Earlier this year, I announced the release of a brand-new Dock Manager component in the Ignite UI for Web Components product.  As you may know, web components are web standards compliant components that are dependency free, pure HTML/JavaScript, and are seen as a native HTML element.  This means that Infragistics is the first component vendor to provide a Dock Manager component that will work with any web framework including Angular, Vue, React, and Blazor just to name a few.

What is a dock manager?

Well, if you have ever used Visual Studio you know exactly what it is. If you haven’t, it’s a component that provides a way to manage a complex layout using different type of panes with various sizes, positions, and behaviors, and that can be docked to various locations within an app. The dock manager allows your end-users to customize it further by pinning, resizing, moving, floating, and hiding panes.  Besides a data grid, this is a game changer for all web applications.

How to use Dock Manager web component in Blazor?

Now the question is, “How do I use this awesome Dock Manager web component in my Blazor applications?”. Great question!  I’m going to walk you through all the step necessary to utilize the Ignite UI for Web Components Dock Manager in your Blazor applications. We’ll be using a combination of HTML, JavaScript, C#, and Blazor’s JS Interop. Let’s get to it!

Create a New Blazor Application

The first step is to create a new Blazor application. I am going to use Visual Studio 2019 to create a new Blazor Web Assembly App (WASM). I named my project “BlazorDockManagerWC”.

 create a new blazor web assembly application in visual studio

Create a JavaScript File

The first step is to create a JavaScript file in the “wwwroot” folder of our project. I named my JavaScript file “dockmanager.js” and placed it in a “scripts” folder.  This will be the file to hold all of our JavaScript functions for the Blazor dock manger.

 create javascript file in Blazor app

Update index.html

After we have created the JavaScript file, lets open the “index.html” page and import our script. We will want to make sure we import the script as a “module”.

 add javascript reference to index.html as type module

Import the Dock Manager WC

Now, we want to open our “dockmanager.js” JavaScript file and import the Ignite UI for Web Component Dock Manager.  The Dock Manager web component is available on NPM as a trial package. We will use “unpkg.com” to import the dock manager into our script. Unpkg is a fast, global content delivery network for everything on npm. You can use it to load any file quickly and easily from any package on npm.

import { defineCustomElements } from 'https://unpkg.com/igniteui-dockmanager@1.0.3/loader/index.mjs';
defineCustomElements();

Create the Dock Manager

Open the “Index.razor” file in your Blazor application and define the dock manager web component. Within the opening and closing tag of the Dock Manager component, we will define several DIVs to act as our docking panes within the dock manager component. Each DIV will host various content that will be displayed in our dock manager component.

<igc-dockmanager @ref="dockManager" style="height:800px;">
    <div slot="content1">Content 1</div>
    <div slot="content2">Content 2</div>
    <div slot="content3">Content 3</div>
    <div slot="content4">Content 4</div>
    <div slot="content5">Content 5</div>
    <div slot="content6">Content 6</div>
    <div slot="content7">Content 7</div>
    <div slot="content8">Content 8</div>
    <div slot="content9">Content 9</div>
</igc-dockmanager>

As you can see, we have defined an “@ref” value on the dock manager which will allow us to access the dock manager in our C# code later, and we have also set a default height using an inline style.

I also want to point out that on each DIV element we have set the “slot” property which is used to uniquely identify each div as a pane in the dock manager. This is required, so don’t forget this step.

Create Dock Manager Helper Functions

Open the “dockmanager.js” JavaScript file and create a few helper functions that we will use to create content panes, split panes, and tabbed panes that will control the layout of the DIVs in the dock manager component.

function createContentPane(contentID, paneHeader) {
    const pane = {
        header: paneHeader,
        type: "contentPane",
        contentId: contentID
    };
    return pane;
}

function createSplitPane(orientation, contentPanes, size) {
    const pane = {
        type: "splitPane",
        orientation: orientation,
        panes: contentPanes,
        size: size
    };
    return pane;
}

function createTabPane(orientation, contentPanes, size) {
    const pane = {
        type: "documentHost",
        size: size,
        rootPane: {
            type: "splitPane",
            orientation: orientation,
            panes: [
                {
                    type: "tabGroupPane",
                    panes: contentPanes
                }
            ]
        }
    };
    return pane;
}

Define the Dock Manager Layout

Now that we have our help methods defined in our JavaScript file, we can start creating the layout for the DIV elements within our dock manager component.  Let’s start by creating a new function called “initDockManager” that accepts a dock manager as an argument.

window.initDockManager = function (dockmanager) {   

};

NOTE: Since we must use JS Interop in Blazor in order to interact with our dock manager web components, you have to make sure you declare the “initDockManager” function on the “window” object.

Next, let’s create the various dock manager panes using our help functions we created earlier.  Since we have nine DIV elements within the dock manager component in our “index.razor” file, we will have at least nine content panes. We will then use a combination of tabbed panes, split panes, and content panes to lay them out.

    const pane1 = createContentPane('content1', 'Content Pane 1');
    const pane2 = createContentPane('content2', 'Unpinned Pane 1');
    pane2.isPinned = false;

    const pane3 = createContentPane('content3', 'Document 1');
    const pane4 = createContentPane('content4', 'Document 2');

    const contentPane5 = createContentPane('content5', 'Unpinned Pane 2');
    contentPane5.isPinned = false;

    const pane6 = createContentPane('content6', 'Tab 1');
    const pane7 = createContentPane('content7', 'Tab 2');
    const pane8 = createContentPane('content8', 'Content Pane 2');
    const pane9 = createContentPane('content9', 'Floating Pane');

    const tabPane1 = createTabPane("horizontal", [pane3, pane4], 200);

    const splitPane1 = createSplitPane("vertical", [pane1, pane2]);
    const splitPane2 = createSplitPane("vertical", [tabPane1, contentPane5], 200);

Now that we have all our panes created, we need to define the layout of the dock manager component using these panes. Using the “dockManager” function parameter, we will set the layout property using a combination of content panes, tabbed panes, split panes, and floating panes to define the layout of the dock manager component.

    dockmanager.layout = {
        rootPane: {
            type: "splitPane",
            orientation: "horizontal",
            panes: [
                splitPane1,
                splitPane2,
                {
                    type: "splitPane",
                    orientation: "vertical",
                    panes: [
                        {
                            type: "tabGroupPane",
                            size: 200,
                            panes: [pane6, pane7]
                        },
                        pane8
                    ]                    
                }
            ]
        },
        floatingPanes: [
            {
                type: "splitPane",
                orientation: "horizontal",
                floatingHeight: 150,
                floatingWidth: 250,
                floatingLocation: { x: 800, y: 250 },
                panes: [pane9]
            }
        ]
    }

This is what the entire “initDockManager” function looks like:

window.initDockManager = function (dockmanager) {

    const pane1 = createContentPane('content1', 'Content Pane 1');
    const pane2 = createContentPane('content2', 'Unpinned Pane 1');
    pane2.isPinned = false;

    const pane3 = createContentPane('content3', 'Document 1');
    const pane4 = createContentPane('content4', 'Document 2');

    const contentPane5 = createContentPane('content5', 'Unpinned Pane 2');
    contentPane5.isPinned = false;

    const pane6 = createContentPane('content6', 'Tab 1');
    const pane7 = createContentPane('content7', 'Tab 2');
    const pane8 = createContentPane('content8', 'Content Pane 2');
    const pane9 = createContentPane('content9', 'Floating Pane');

    const tabPane1 = createTabPane("horizontal", [pane3, pane4], 200);

    const splitPane1 = createSplitPane("vertical", [pane1, pane2]);
    const splitPane2 = createSplitPane("vertical", [tabPane1, contentPane5], 200);

    dockmanager.layout = {
        rootPane: {
            type: "splitPane",
            orientation: "horizontal",
            panes: [
                splitPane1,
                splitPane2,
                {
                    type: "splitPane",
                    orientation: "vertical",
                    panes: [
                        {
                            type: "tabGroupPane",
                            size: 200,
                            panes: [pane6, pane7]
                        },
                        pane8
                    ]                    
                }
            ]
        },
        floatingPanes: [
            {
                type: "splitPane",
                orientation: "horizontal",
                floatingHeight: 150,
                floatingWidth: 250,
                floatingLocation: { x: 800, y: 250 },
                panes: [pane9]
            }
        ]
    }
};

Use Blazor JS Interop to Initialize the Dock Manager

The final step is to take advantage of Blazor’s JS Interop feature to call our “initDockManager” JavaScript function we have defined in our “dockmanagerjs” JavaScript file.

Step one is to inject the IJSRuntime into our “Index.Razor” file where we have defined our dock manager component. To do this, we simply add “@inject IJSRuntime JSRuntime” to the top of our “Index.razor” file.

 @inject IJSRuntime JSRuntime

Step two is to modify the @code section of our “Index.razor” file to call the “initDockManager” JavaScript function we created earlier.

Remember the “@ref” we added to our dock manager component earlier in the post? This is where we want to make sure we have defined an ElementReference called dockManager in our “@code” section.

 elementreference code snippet

Now, let’s override the OnAfterRenderAsync method, and make a call to the JSInterop.InvokeVoidAsync method passing our dockManager ElementReference as an argument.  The entire @code section of the “Index.razor” file should look like this:

@code{

    ElementReference dockManager;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            await JSRuntime.InvokeVoidAsync("initDockManager", dockManager);
        }
    }
}

Run the Blazor Application

That’s it! We’re all done. Now is the time to see the fruits of our labor in action. Run the application and watch in awe as the Ignite UI Dock Manager comes to life in our Blazor application. 

Isn’t it beautiful?

  Ignite UI Blazor Dock Manager

If you'd like to get the source code to this project, you can find here: https://github.com/brianlagunas/BlazorDockManagerWC

Be sure to follow and contact me directly on Twitter, subscribe to my YouTube channel, and follow me on Twitch to watch me stream live.