☝️Small business or a startup? See if you qualify for our special offer.
+
All documentation
  • Introduction
  • Connecting to data source
  • Browser compatibility
  • Documentation for older versions
  • Creating a custom UI control or view

    This guide describes how to create a custom UI control or view for Flexmonster if the needed UI functionality is not provided out of the box. For example, you can create a custom filter view or a report picker. To see different examples of custom controls and views, visit our Examples page.

    You can also add custom functionality to the Toolbar or the context menu.

    General approach

    Step 1. Сreate an HTML structure to represent your control, such as a pop-up window, container, dropdown, button, etc.

    Step 2. Use the Flexmonster API getter methods to retrieve the component’s state. For example:

    See the full list of Flexmonster API calls.

    Step 3. Implement your custom functionality. If you need to track Flexmonster’s state and user actions, use Flexmonster events.

    Step 4. Apply changes to the component using Flexmonster API setter methods (e.g., setReport() or runQuery() to set the slice). See the full list of Flexmonster API calls.

    Example 1. Creating a custom report picker

    In this example, we create a custom report picker and a layout picker Live example.

    Step 1. Prepare the necessary reports: you can configure them via the UI and then save (e.g., as a variable in code or as a file on the server). In our case, we define reports as a set of functions that return the ReportObject:

    function happinessReport() {
    return {
    dataSource: {
    type: "csv",
    filename: "https://cdn.flexmonster.com/data/happiness.csv",
    },
    slice: {
    // Slice configs
    },
    options: {
    // Options configs
    },
    // Other configs
    };
    }

    Step 2. Create an HTML element that will be used as a picker (e.g., a set of buttons or a dropdown menu). In our example, we create two sets of buttons. The first set will be used to choose the report, and the second one for switching layouts.

    Step 3. For the first set of buttons, implement a function that will switch the reports on the grid using the setReport() API call. If you store reports on the server, you can use the load() method.

    Check out an example:

    function openReport(data) {
    let report = "";

    switch (data) {
    case "happiness":
    report = happinessReport();
    break;
    // Other cases
    }

    // Sets the chosen view type after switching the reports
    switch (viewType) {
    case "flat":
    report.options.viewType = "grid";
    report.options.grid.type = "flat";
    break;
    // Other cases
    }

    pivot.setReport(report);
    }

    Step 4. For the second set of buttons, create a function that changes the layout. Use the getOptions(), setOptions(), and refresh() API calls:

    function changeView(view) {
    viewType = view;
    let options = pivot.getOptions();

    switch (view) {
    case "flat":
    options.viewType = "grid";
    options.grid.type = "flat";
    break;
    case "pivot":
    options.viewType = "grid";
    options.grid.type = "compact";
    break;
    case "charts":
    options.viewType = "charts";
    break;
    }

    pivot.setOptions(options);
    pivot.refresh();
    }

    You can also explore an example of a report picker implemented as a dropdown menu and integrated into the Toolbar Live example.

    Example 2. Creating a custom Options pop-up window

    This example describes how to create the Options pop-up window with custom functionality Live example.

    Step 1. Create an HTML element that will represent your custom Options pop-up window. Add controls for selecting the new option values, e.g., dropdowns.

    Step 2. Create a function that opens the pop-up window. In this function, set the current option values in the UI control using the getOptions() API call. Your code should look similar to the following:

    function showOptionsPopup() {
    const popup = document.querySelector("#custom-options-popup");
    const popupOverlay = document.querySelector("#popupOverlay");

    // Get current Flexmonster options
    const options = pivot.getOptions().grid;

    // Set current values to the select elements
    document.getElementById("custom-options-grand-totals-select").value = options.showGrandTotals ?? "on";
    document.getElementById("custom-options-subtotals-select").value = options.showTotals ?? "on";
    document.getElementById("custom-options-layout-select").value = options.type ?? "compact";

    popup.classList.remove("hideCustomPopup");
    popupOverlay.classList.remove("hideCustomPopup");

    popupOverlay.onclick = closeOptionsPopup;
    }

    Step 3. Add a function that closes the pop-up window.

    Step 4. When the user clicks the APPLY button, apply new options using the getOptions() and setOptions() API calls. Use refresh() to update the grid with the new options. You can structure your code as follows:

    function submitOptions() {
    const grandTotalsSelect = document.getElementById("custom-options-grand-totals-select");
    const subtotalsSelect = document.getElementById("custom-options-subtotals-select");
    const layoutSelect = document.getElementById("custom-options-layout-select");

    // Get the selected values
    const grandTotalsValue = grandTotalsSelect.value;
    const subtotalsValue = subtotalsSelect.value;
    const layoutValue = layoutSelect.value;

    let options = pivot.getOptions();
    options.grid.type = layoutValue;
    options.grid.showTotals = subtotalsValue;
    options.grid.showGrandTotals = grandTotalsValue;
    pivot.setOptions(options);
    pivot.refresh();
    closeOptionsPopup();
    }

    Step 5. (optional) To replace the default Options pop-up window with a custom one, handle the beforetoolbarcreated event.

    Example 3. Creating a custom Field List

    In this example, we create a custom Field List where the user can edit only the Rows and Report Filters boxes Live example.

    Step 1. Create an HTML element for your custom Field List. In this element, create three <div> elements, which will represent:

    • The Available fields list.
    • The Rows list.
    • The Report Filters list.

    We will fill these elements with fields in the following steps.

    Step 2. Implement a function that returns fields that are not currently used in the pivot table. These fields will be rendered in the Available fields box:

    function getAvailableFields() {
    // Get all fields
    const allFields = pivot.getAllHierarchies();

    // Get fields that are already present in the slice
    const columns = pivot.getColumns().map((col) => col.uniqueName);
    const measures = pivot.getMeasures().map((measure) => measure.uniqueName);
    const rows = pivot.getRows().map((row) => row.uniqueName);
    const filters = pivot.getReportFilters().map((f) => f.uniqueName);

    // Filter out fields that are already used
    return allFields.filter(
    (field) =>
    !columns.includes(field.uniqueName) &&
    !measures.includes(field.uniqueName) &&
    !rows.includes(field.uniqueName) &&
    !filters.includes(field.uniqueName)
    );
    }

    This function uses the following API calls: getAllHierarchies(), getRows(), getColumns(), getMeasures(), and getReportFilters().

    Step 3. Create a function (e.g., openFieldList()) that opens the Field List. In this function, get the fields that will be rendered:

    function openFieldList() {
    const availableFields = getAvailableFields();
    const currentRows = pivot.getRows();
    const currentFilters = pivot.getReportFilters();

    document.getElementById("field-list").style.display = "block";
    backdrop.style.display = "block";
    }

    Step 4. Inside openFieldList(), define a helper function that renders the fields:

    function openFieldList() {
    const availableFields = getAvailableFields();
    const currentRows = pivot.getRows();
    const currentFilters = pivot.getReportFilters();

    const renderFields = (containerId, fields) => {
    const container = document.getElementById(containerId);

    const header = container.querySelector("h3")?.outerHTML || ""
    container.innerHTML = header

    fields.forEach((field) => {
    const item = document.createElement("div");
    item.className = "draggable-field";
    item.draggable = true;
    item.innerText = field.caption;
    item.dataset.uniqueName = field.uniqueName;
    container.appendChild(item);
    });
    };

    renderFields("available-fields", availableFields);
    renderFields("rows", currentRows);
    renderFields("report-filters", currentFilters);

    document.getElementById("field-list").style.display = "block";
    backdrop.style.display = "block";
    }

    Step 5. Implement drag and drop. When the field is dropped into a certain box, save this field to the corresponding array. Also, remove the relocated field from the Available fields box.

    Step 6. When the user clicks the APPLY button, call the runQuery() method to set a new report:

    function applySlice() {
    const rows = [...document.getElementById("rows").children].map((el) => ({
    uniqueName: el.dataset.uniqueName,
    }))

    const reportFilters = [...document.getElementById("report-filters").children].map(
    (el) => ({
    uniqueName: el.dataset.uniqueName,
    }),
    )

    // Get the current columns and measures from the component so they remain unchanged
    const columns = pivot.getColumns();
    const measures = pivot.getMeasures();

    pivot.runQuery({
    rows,
    reportFilters,
    columns,
    measures,
    })

    closeFieldList();
    }

    See also