Skip to content

Embed a Qlik Sense sheet using qlik-embed web components

Overview

In this tutorial, you’ll learn how to embed a sheet from a Qlik Sense app using qlik-embed, rather than the Capability API or iframe. While embedding a sheet is simpler using Capability API, this example demonstrates additional capability provided with the qlik-api.

A sheet in a Qlik Sense app is a container for one-to-many visualizations, and the sheet’s layout is accessible metadata in JSON that you can read to recreate the sheet programmatically. The benefit of this approach is that the layout of the sheet is created dynamically in the client and propagated to your web application without using an iframe.

Prerequisites

To use the example page in this guide, ensure that you have the following:

Variable substitution and vocabulary

Throughout this tutorial, variables will be used to communicate value placement. The variable substitution format is VARIABLE_NAME or <VARIABLE_NAME>. Here is a list of variables that appear in the sample code.

VariableDescription
QLIK_TENANT_URLThe domain for the tenant you are accessing. Equivalent to tenant.region.qlikcloud.com.
QLIK_OAUTH_CLIENT_IDThe clientId of the OAuth SPA you configured.
QLIK_REDIRECT_URIThe Redirect URL for the OAuth2 client to provide an access token.
QLIK_APP_IDThe unique identifier of the application.
QLIK_SHEET_IDThe unique identifier of the sheet.

This example loads these values from process.env, which you can set in a .env file and reference when running the example with node.js 20+ using node --env-file=.env server.js.

Sequence

The code example in this tutorial provides a basic, fully functional web page that executes the following sequence:

  1. Handles logging in to Qlik.
  2. Loads the qlik-embed web components and qlik-api resources.
  3. Connects to the app.
  4. Retrieves the sheet layout.
  5. Sets a target div with a CSS grid that matches the sheet’s layout.
  6. Iterates over each object within the sheet layout, creating a div for each and setting it with the same grid position as in the layout. This process also sets the id of each div to the objectId of the Qlik object.
  7. Iterates over each div and injects each Qlik object whose objectId matches the corresponding id.

Full example code

Below is an example built using qlik-api and qlik-embed web components.

Style sheet: web-component-sheet.css

body,
html {
    margin: 0;
    padding: 0;
    font-family: sans-serif;
    font-size: 14px;
    background-color: #f5f5f5;
    color: #333;
    height: 100%;
    width: 100%;
}

div.flex-container {
    display: flex;
    flex-wrap: wrap;
    margin: 0 45px 45px 0;
}

div.qvobject {
    flex: 1 1 auto;
    height: 300px;
    min-width: 400px;
    margin: 45px 0 0 45px;
}

JavaScript: web-component-sheet.js

import { auth, qix } from "https://cdn.jsdelivr.net/npm/@qlik/api/index.js";


// Retrieve settings from environment
const QLIK_TENANT_URL = process.env.QLIK_TENANT_URL;
const QLIK_OAUTH_CLIENT_ID = process.env.QLIK_OAUTH_CLIENT_ID;
const QLIK_APP_ID = process.env.QLIK_APP_ID;
const QLIK_SHEET_ID = process.env.QLIK_SHEET_ID;
const QLIK_REDIRECT_URI = process.env.QLIK_REDIRECT_URI;


// OAuth authentication settings
const hostConfig = {
    host: QLIK_TENANT_URL,
    authType: "oauth2",
    clientId: QLIK_OAUTH_CLIENT_ID,
    redirectUri: QLIK_REDIRECT_URI
};

auth.setDefaultHostConfig(hostConfig);


//    DEFAULT PLACEMENT CONFIGURATION
const qlikDivSelector = "#sheet";
const qlikObjectClass = "qlikObject";


//    MAIN
(async function main() {
    const app = await doCapabilities(qlikDivSelector, qlikObjectClass);
})();


// CREATE GRID
function createGrid(querySelector, columns, rows) {
    const gridContainer = document.querySelector(querySelector);
    gridContainer.style.display = "grid";
    gridContainer.style.gridTemplateRows = `repeat(${rows}, minmax(0, 1fr)`;
    gridContainer.style.gridTemplateColumns = `repeat(${columns}, minmax(0, 1fr))`;

    return gridContainer;
}


// CONSTRUCT SHEET
function constructSheet(sheetLayout, querySelector, addClass) {
    const gridContainer = createGrid(querySelector, sheetLayout.columns, sheetLayout.rows);
    sheetLayout.cells.forEach(function (object) {
        const objectId = object.name;
        const colStart = object.col + 1;
        const rowStart = object.row + 1;
        const colSpan = object.colspan;
        const rowSpan = object.rowspan;
        const objectDiv = document.createElement("div");
        objectDiv.id = objectId;
        objectDiv.style["grid-column"] = `${colStart} / span ${colSpan}`;
        objectDiv.style["grid-row"] = `${rowStart} / span ${rowSpan}`;
        objectDiv.style.border = "2px solid #0000";
        objectDiv.style.margin = "5px";
        objectDiv.style.width = "100%";
        objectDiv.classList.add(addClass);
        gridContainer.appendChild(objectDiv);
    });
    return true;
}


// LOAD & RENDER CAPABILITIES
async function doCapabilities(qlikDivSelector, objectClass) {
    try {
        const session = qix.openAppSession(QLIK_APP_ID);
        const app = await session.getDoc();
        if (app) {
            const sheetObject = await app.getObject(QLIK_SHEET_ID);
            const sheetLayout = await sheetObject.getLayout();
            constructSheet(sheetLayout, qlikDivSelector, objectClass);
            const elements = document.querySelectorAll(`.${objectClass}`);
            elements.forEach(async (element) => {
                const qlikdiv = document.createElement("qlik-embed");
                qlikdiv.setAttribute("ui", "analytics/chart");
                qlikdiv.setAttribute("app-id", QLIK_APP_ID);
                qlikdiv.setAttribute("object-id", element.getAttribute("id"));
                document.querySelector(`#${element.getAttribute("id")}`).appendChild(qlikdiv);
            });
        }
    } catch (error) {
        console.error("Error in doCapabilities:", error);
    }
}

HTML: web-component-sheet.html

<!doctype html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <script src="https://cdn.jsdelivr.net/npm/@qlik/embed-web-components@1/dist/index.min.js"></script>
    <link rel="stylesheet" href="web-component-sheet.css" />
</head>

<body>
    <div id="sheet" style="height: 1200px;"></div>
    <script type="module" src="web-component-sheet.js"></script>
</body>

</html>

Was this page helpful?