Pricing changes are coming in January. Contact our Sales team to secure the current price for your desired license.
All documentation
  • Introduction
  • Connecting to data source
  • Browser compatibility
  • Documentation for older versions
  • Customizing the grid cells

    In addition to CSS themes that change the appearance of the whole component, Flexmonster provides functionality for advanced grid customization. The customizeCell() API call allows adding new styles and functionality to columns, rows, or specific cells.

    The general idea of cell customization

    The customizeCell() method allows you to set a function that will be triggered for each table cell during rendering.

    Inside the function, information about the cell (e.g., the cell's position on the grid) can be accessed using the data parameter. Based on that information, you can customize the cell's representation or functionality through the cell parameter of the function. For example, it is possible to add HTML attributes, classes, inline CSS styles, and change the cell's text.

    See an example that demonstrates how the function for cell customization is triggered for every table cell by painting the cell in a unique color Live example.

    This guide contains several use cases of cell customization. However, they do not demonstrate all the customization possibilities. To see more examples, visit the Examples page.

    Alternating row colors

    Using customizeCell(), you can alternate row colors on the grid.

    In this example, we will alternate colors by adding a class to cells based on their row index (data.rowIndex). The customizeCellFunction() can be defined in the following way:

    function customizeCellFunction(cell, data) {
    if (data.type == "value") {
    if (data.rowIndex % 2 == 0) {
    cell.addClass("alter");
    } else {
    return;
    }
    }
    }

    Then we need to define CSS for the class added to cells:

    #fm-pivot-view .fm-grid-view div.alter {
    background-color: #e1e1e1;
    }

    In this example, the CSS class is applied only to cells where data.type is "value", which means that the cell contains numeric data.

    Live example

    In a similar way, you can alternate column colors based on column indexes (data.columnIndex).

    Styling subtotals and grand totals

    Totals in rows and columns can be styled independently. The data parameter has the following properties that specify if the cell is subtotal or grand total:

    Based on the values of these properties in each cell, a CSS class can be added to it. Here is an example:

    function customizeCellFunction(cell, data) {
    if (data.isClassicTotalRow) {
    cell.addClass("fm-total-classic-r");
    }
    }

    The CSS code sample:

    #fm-pivot-view .fm-grid-view .fm-total-classic-r {
    background-color: #B2DBBF;
    }

    Live example

    Highlighting cells based on their data

    The data parameter has measure, rows, and columns properties that contain info about the cell's semantics. Check out several use cases of these properties below.

    Highlighting a certain member on the grid

    You can highlight cells that contain info about a certain member regardless of the cell's position:

    const highlightedMembers = {
    "Country": ["Canada", "Germany"],
    "Business Type": ["Warehouse"]
    }

    function customizeCellFunction(cell, data) {
    if (data.rows) {
    data.rows.forEach(row => {
    if (highlightedMembers[row.hierarchyName] &&
    highlightedMembers[row.hierarchyName].includes(row.caption)) {
    cell.addClass("highlight");
    }
    });
    }
    if (data.columns) {
    data.columns.forEach(column => {
    if (highlightedMembers[column.hierarchyName] &&
    highlightedMembers[column.hierarchyName].includes(column.caption)) {
    cell.addClass("highlight");
    }
    });
    }
    }

    After the highlight class was added, the following CSS selector can be written:

    .highlight {
    background-color: #FFB74D !important;
    }

    Live example

    Highlighting a certain measure on the grid

    Cells can be highlighted differently depending on the measure they are related to.

    For example, you can add information about a cell's measure to the cell's attribute:

    function customizeCellFunction(cell, data) {
    if (data.measure) {
    cell.attr["measure"] = data.measure.name;
    }
    }

    Now that each HTML cell will have the measure attribute, we can add CSS selectors to highlight the rows with different colors depending on their measure:

    #fm-pivot-view .fm-grid-view div[measure="Price"] {
    background-color: #80CBC4 !important;
    }

    #fm-pivot-view .fm-grid-view div.fm-cell[measure="Quantity"] {
    background-color: #FFCC80 !important;
    }

    #fm-pivot-view .fm-grid-view div.fm-cell[measure="Discount"] {
    background-color: #81D4FA !important;
    }

    Live example

    Highlighting cells based on different semantic info

    You can customize cells based on different semantic information. For example, add information about the cell's measure, row tuple, and column tuple to the cell's attributes:

    function customizeCellFunction(cell, data) {
    // Add an attribute for the cell's measure
    if (data.measure) {
    cell.attr.measure = data.measure.name;
    }

    // Add attributes for the cell's row tuple
    if (data.rows) {
    for (var i = 0; i < data.rows.length; i++) {
    cell.attr["hierarchy-r-" + i] = data.rows[i]["hierarchyCaption"];
    cell.attr["member-r-" + i] = data.rows[i]["caption"];
    }
    }

    // Add attributes for the cell's column tuple
    if (data.columns) {
    for (var i = 0; i < data.columns.length; i++) {
    cell.attr["hierarchy-c-" + i] = data.columns[i].hierarchyCaption;
    cell.attr["member-c-" + i] = data.columns[i].caption;
    }
    }
    }

    Then you can add CSS selectors that apply different styles to cells depending on the attribute values:

    #fm-pivot-view .fm-grid-view div.fm-cell[hierarchy-r-0="Country"][member-r-0="Canada"] {
    background-color: #E1E1E1;
    }

    #fm-pivot-view .fm-grid-view div.fm-cell[measure="Price"],
    #fm-pivot-view .fm-grid-view div.fm-cell.fm-header[measure="Price"] {
    color: #C00000;
    }

    Live example

    In this way, you can apply multiple styles to the cell depending on the information it contains.

    Adding images to cells

    The customizeCell() method allows you to display images in cells via the cell.text property.

    In this case, we replaced cell values with icons. The icons depend on the interval the value belongs to: very low (below 5), low (between 5 and 10), middle (between 10 and 25), high (between 25 and 50), very high (above 50). See the code below:

    function customizeCellFunction(cell, data) {
    // Customize only value cells in the compact, classic (tabular), and flat forms
    if (data && data.type === "value" && !data.isDrillThrough) {
    // Very low interval
    if (data.value < 5) {
    cell.text = `<img src="https://cdn.flexmonster.com/i/empty_pie.svg" class="centered">`;
    }
    // Code for other intervals
    // ...
    }
    }

    Live example

    You can add links to cells via the cell.text property. For example, here's how to add links to all the countries in the report using this property:

    function customizeCellFunction(cell, data) {
    // Step 1. Skip a cell if it doesn't contain a country name
    if (!(data.hierarchy && data.hierarchy.uniqueName == "Country")) return;

    // Step 2. Create a link to the country's Wikipedia page
    let newText =
    `<a href='https://en.wikipedia.org/wiki/${data.escapedLabel}' target='_blank' class='link' onclick='preventExpand(event)'>${data.escapedLabel}</a>`;

    // Step 3.1. Handle cells in the pivot table
    if (data.type == "header" && data.member) {
    let parts = cell.text.split(data.escapedLabel);
    if (parts.length == 2) {
    newText = parts[0] + newText + parts[1];
    }
    cell.text = newText;
    }
    // Step 3.2. Handle cells the flat table and the drill-through view
    else if (data.type == "value" && (data.member || data.isDrillThrough)) {
    cell.style['z-index'] = 1;
    cell.text = newText;
    }
    }

    Live example

    Customizing cells based on conditional formatting

    It is possible to customize a cell based on conditional formatting rules applied to the cell. This information is contained in the data.conditions property.

    The example in this section shows how to style an entire row based on the conditional formatting rule that applies to a cell in this row. The idea is the following:

    1. For each cell, check if a conditional formatting rule is applied to it using the data.conditions property.
    2. If a conditional rule is applied to the cell, record the cell’s row index.
    3. Create a variable with a CSS selector that will style rows with the previously recorded index.
    4. In the selector, use CSS styles of the applied conditional formatting rule (can be found in the rule’s formatCSS property).
    5. Add the prepared CSS to a <style> tag.
    6. Apply the created <style> tag to the page with the component in the aftergriddraw event’s handler.
    Expand to see the example's code
    const pivot = new Flexmonster({
    // Other configs
    // ...
    customizeCell: customizeCellFunction,
    beforegriddraw: function (e) {
    if (e.smooth == false) {
    shouldCleanStyles = true;
    }
    },
    // Apply styles to the component
    aftergriddraw: function (e) {
    addExtraStyles();
    },
    });

    let shouldCleanStyles = false;
    let shouldAddStyles = false;
    let rowsWithCondition = {};
    let conditions = [];
    let styleTag;

    // Remove previously applied styles
    function cleanExtraStyles() {
    // ...
    }

    // Add the tag with custom CSS to the HTML page
    function addExtraStyles() {
    if (styleTag && shouldAddStyles) {
    shouldAddStyles = false;
    cleanExtraStyles();
    document.head.appendChild(styleTag);
    }
    }

    function customizeCellFunction(cell, data) {
    // Additional configs
    // ...

    // Check if at least one conditional formatting rule applies to the cell
    // and if the cell's row was not customized before
    if (hasConditions(data.conditions) && !wasRowCustomized(data.rowIndex)) {
    // Create an HTML tag for CSS styles
    if (!styleTag) {
    shouldAddStyles = true;
    styleTag = document.createElement("style");
    }

    // Record that this row's been customized
    rowsWithCondition.push(data.rowIndex);

    // Get the last conditional formatting rule that applies to the cell
    const conditionId = data.conditions.at(-1);
    const condition = getCondition(conditionId);
    if (condition == null) return;

    // Specify a CSS selector for the header cell in the row
    let style =
    ".fm-grid-layout div.fm-cell.fm-header-r[data-r='" +
    data.rowIndex +
    "']:not([data-c='-1']), ";
    // Specify a CSS selector for other cells in the row
    style +=
    ".fm-grid-layout div.fm-cell[data-r='" +
    data.rowIndex +
    "']:not([data-c='-1']):not(.fm-empty)";
    // Convert the cell's conditional formatting rule to CSS and apply it to the cell's row
    style +=
    "{ " + condition.formatCSS.replace(/;/gi, " !important;") + " }";
    // Add the created CSS to the <style> tag
    styleTag.innerHTML += style;
    }
    }

    Live example

    Removing customization

    To remove customization, call the customizeCell() method with the null input parameter:

    pivot.customizeCell(null);

    Live example

    See also