List of all demos

React pivot table: live data update

Our pivot table component for React can update your data in real-time.


    import React from "react";
    import * as FlexmonsterReact from "react-flexmonster";
    
    class PivotTableDemo extends React.Component {
      render() {
        return (
          <>
            <FlexmonsterReact.Pivot
              ref={this.pivot}
              height={450}
              report={this.report}
              customizeCell={this.customizeCellFunction}
              reportcomplete={() => {
                this.pivot.current.flexmonster.off("reportcomplete");
                this.getData();
                this.updateData();
                setInterval(() => {
                  this.updateData();
                }, 6000);
              }}
            />
          </>
        );
      }
    
      constructor(props) {
        super(props);
        this.pivot = React.createRef();
        this.report = {
          dataSource: {
            type: "json",
            data: [
              {
                "ID": "ISK",
                "Currency": "ISK",
                "Bid Rate": 136.02732,
                "Ask Rate": 136.02732,
              },
            ],
            mapping: {
              "ID": {
                type: "id",
              },
              "Currency": {
                type: "string",
                caption: "Currency",
              },
              "Bid Rate": {
                type: "number",
              },
              "Ask Rate": {
                type: "number",
              },
            },
          },
          slice: {
            rows: [
              {
                uniqueName: "Currency",
                sort: "asc",
              },
            ],
            columns: [
              {
                uniqueName: "[Measures]",
              },
            ],
            measures: [
              {
                uniqueName: "Bid Rate",
                aggregation: "sum",
                format: "rate_format",
              },
              {
                uniqueName: "Ask Rate",
                aggregation: "sum",
                format: "rate_format",
              },
            ],
            flatOrder: ["Bid Rate", "Currency", "Ask Rate"],
          },
          options: {
            grid: {
              type: "flat",
              showFilter: false,
              showHeaders: false,
              showTotals: "off",
              showGrandTotals: "off",
            },
            configuratorButton: false,
            drillThrough: false,
          },
          conditions: [
            {
              formula: "if(#updateDifference < 0, 'fm-updated-cell-down', 'fm-updated-cell-up')",
            },
          ],
          formats: [
            {
              name: "rate_format",
              decimalPlaces: 4,
              textAlign: "left",
              thousandsSeparator: ",",
              decimalSeparator: ".",
            },
          ],
          tableSizes: {
            columns: [
              {
                tuple: ["Currency"],
                width: 200,
              },
              {
                tuple: ["Bid Rate"],
                width: 200,
              },
              {
                tuple: ["Ask Rate"],
                width: 200,
              },
            ],
          },
        };
        this.currency_data = {
          "base": "EUR",
          "date": "2019-02-25",
          "rates": {
            "AED": 4.1643,
            "AFN": 84.5209,
            "ALL": 124.678,
            "AMD": 554.211,
            "ANG": 2.046,
            "AOA": 356.192,
            "ARS": 44.171,
            "AUD": 1.581,
            "AWG": 2.041317,
            "AZN": 1.933087,
            "BAM": 1.951296,
            "BBD": 2.258204,
            "BDT": 95.400537,
            "BGN": 1.954755,
            "BHD": 0.427422,
            "BIF": 2069.094139,
            "BMD": 1.13375,
            "BND": 1.531244,
            "BOB": 7.835064,
            "BRL": 4.233539,
            "BSD": 1.13392,
            "BTC": 0.000295,
            "BTN": 80.316392,
            "BWP": 11.923596,
            "BYN": 2.421119,
            "BYR": 22221.50418,
            "BZD": 2.285526,
            "CAD": 1.495887,
            "CDF": 1849.145964,
            "CHF": 1.135042,
            "CLF": 0.028398,
            "CLP": 736.823969,
            "CNY": 7.584107,
            "COP": 3513.832036,
            "CRC": 689.48953,
            "CUC": 1.13375,
            "CUP": 30.044381,
            "CVE": 110.535542,
            "CZK": 25.640665,
            "DJF": 201.49075,
            "DKK": 7.460864,
            "DOP": 57.407458,
            "DZD": 134.485261,
            "EGP": 19.893917,
            "ERN": 17.005966,
            "ETB": 32.447734,
            "EUR": 1,
            "FJD": 2.411826,
            "FKP": 0.861639,
            "GBP": 0.86868,
            "GEL": 3.032784,
            "GGP": 0.86856,
            "GHS": 6.06658,
            "GIP": 0.861639,
            "GMD": 56.182966,
            "GNF": 10464.51457,
            "GTQ": 8.747903,
            "GYD": 237.157986,
            "HKD": 8.89842,
            "HNL": 27.816591,
            "HRK": 7.429808,
            "HTG": 92.849617,
            "HUF": 317.886543,
            "IDR": 15850.394857,
            "ILS": 4.089607,
            "IMP": 0.86856,
            "INR": 80.331833,
            "IQD": 1350.296504,
            "IRR": 47736.552753,
            "ISK": 136.02732,
            "JEP": 0.86856,
            "JMD": 148.419352,
            "JOD": 0.80406,
            "JPY": 125.963013,
            "KES": 113.589954,
            "KGS": 78.965538,
            "KHR": 4529.332142,
            "KMF": 491.704489,
            "KPW": 1020.424717,
            "KRW": 1265.627953,
            "KWD": 0.344205,
            "KYD": 0.944936,
            "KZT": 426.652611,
            "LAK": 9733.813543,
            "LBP": 1710.545227,
            "LKR": 203.779877,
            "LRD": 182.675544,
            "LSL": 15.725492,
            "LTL": 3.347669,
            "LVL": 0.685794,
            "LYD": 1.570208,
            "MAD": 10.837289,
            "MDL": 19.423471,
            "MGA": 4031.615903,
            "MKD": 61.43116,
            "MMK": 1729.705727,
            "MNT": 2986.538471,
            "MOP": 9.166594,
            "MRO": 404.74865,
            "MUR": 38.615273,
            "MVR": 17.516396,
            "MWK": 825.954017,
            "MXN": 21.649865,
            "MYR": 4.612319,
            "MZN": 70.921734,
            "NAD": 15.782157,
            "NGN": 410.417537,
            "NIO": 37.078618,
            "NOK": 9.766108,
            "NPR": 128.448243,
            "NZD": 1.647271,
            "OMR": 0.4365,
            "PAB": 1.133807,
            "PEN": 3.747606,
            "PGK": 3.819774,
            "PHP": 58.821793,
            "PKR": 158.464073,
            "PLN": 4.336652,
            "PYG": 6911.795951,
            "QAR": 4.128268,
            "RON": 4.763788,
            "RSD": 118.181746,
            "RUB": 74.335013,
            "RWF": 1003.368939,
            "SAR": 4.252014,
            "SBD": 9.242728,
            "SCR": 15.486461,
            "SDG": 53.994863,
            "SEK": 10.580947,
            "SGD": 1.530674,
            "SHP": 1.49757,
            "SLL": 53943.834921,
            "SOS": 657.574824,
            "SRD": 8.455556,
            "STD": 23866.121798,
            "SVC": 9.921339,
            "SYP": 583.881104,
            "SZL": 15.725163,
            "THB": 35.46594,
            "TJS": 10.692378,
            "TMT": 3.968126,
            "TND": 3.460321,
            "TOP": 2.560744,
            "TRY": 6.012391,
            "TTD": 7.693459,
            "TWD": 34.887776,
            "TZS": 2658.758853,
            "UAH": 30.532255,
            "UGX": 4161.423158,
            "USD": 1.13375,
            "UYU": 37.118517,
            "UZS": 9529.170292,
            "VEF": 11.323328,
            "VND": 26322.278702,
            "VUV": 129.088049,
            "WST": 2.957815,
            "XAF": 654.457601,
            "XAG": 0.071336,
            "XAU": 0.000855,
            "XCD": 3.064017,
            "XDR": 0.813828,
            "XOF": 662.110657,
            "XPF": 119.609776,
            "YER": 283.758118,
            "ZAR": 15.681917,
            "ZMK": 10205.116639,
            "ZMW": 13.549464,
            "ZWL": 365.470062,
          },
        };
        this.dataset = [];
        this.valids = ["EUR", "JPY", "CZK", "DKK", "GBP", "HUF", "UAH", "LTL", "LVL",
        "PLN", "RON", "SEK", "CHF", "NOK", "HRK", "RUB", "TRY", "AUD", "BRL", "CAD",
        "CNY", "HKD", "IDR", "ILS", "INR", "KRW", "MXN", "MYR", "NZD", "PHP", "SGD",
        "THB", "ZAR", "ISK"];
      }
    
      getData = () => {
        let rates = this.currency_data.rates;
    
        Object.entries(rates).forEach(([key, value]) => {
          let record = {};
          record["ID"] = key;
          record["Currency"] = key;
          record["Bid Rate"] = value;
          record["Ask Rate"] = value;
          if (this.valids.indexOf(record["Currency"]) > 0) {
            this.dataset.push(record);
          }
        });
    
        if (this.dataset.length > 0) {
          this.pivot.current.flexmonster.updateData(
            {
              data: this.dataset,
            },
            {
              partial: true,
            }
          );
        }
      };
    
      randomFloatBetween = (minValue, maxValue, precision) => {
        if (typeof precision === "undefined") {
          precision = 4;
        }
    
        return parseFloat(
          Math.min(
            minValue + Math.random() * (maxValue - minValue),
            maxValue
          ).toFixed(precision)
        );
      };
    
      updateData() {
        let numbers = [];
    
        for (let i = 0; i < this.dataset.length; i++) {
          // Generate an array of numbers that are used for indices
          numbers[i] = i;
        }
    
        const shuffleArray = (arr) => {
          return arr
            .map((a) => [Math.random(), a])
            .sort((a, b) => a[0] - b[0])
            .map((a) => a[1]);
        };
    
        let random_permutation = shuffleArray(numbers);
        random_permutation.forEach((index) => {
          let item = this.dataset[index];
          let prev_rate;
          let new_rate;
    
          if (index % 2 === 0) {
            prev_rate = item["Bid Rate"];
            new_rate = prev_rate + this.randomFloatBetween(0.01, 0.3, 3);
            item["Bid Rate"] = new_rate;
            item["Ask Rate"] = new_rate - this.randomFloatBetween(0.01, 0.3, 3);
            this.dataset[index] = item;
          } else {
            prev_rate = item["Bid Rate"];
            new_rate = prev_rate - this.randomFloatBetween(0.01, 0.2, 3);
            if (new_rate > 0) {
              item["Bid Rate"] = new_rate;
              item["Ask Rate"] = new_rate + this.randomFloatBetween(0.01, 0.2, 3);
              this.dataset[index] = item;
            } else {
              new_rate = prev_rate + this.randomFloatBetween(0.01, 0.2, 3);
              item["Bid Rate"] = new_rate;
              item["Ask Rate"] = new_rate - this.randomFloatBetween(0.01, 0.2, 3);
              this.dataset[index] = item;
            }
          }
        });
        this.pivot.current.flexmonster.updateData(
          {
            data: this.dataset,
          },
          {
            partial: true,
          }
        );
      }
    
      customizeCellFunction = (cell, data) => {
        if (data.hierarchy?.uniqueName === "Currency" && data.member) {
          cell.addClass("header-cell");
          let names = data.member.caption.split("/");
          let flag = `<img class="flag" style="width:36px; height:24px;"
            src="https://cdn.flexmonster.com/flags/${names[0].toLowerCase()}.svg">`;
          cell.text = `<div style="display:flex; align-items:center; font-size:12px; 
            position:relative; bottom: 4px;">${flag} ${names[0]}</div>`;
        }
      };
    }
    
    export default PivotTableDemo;
    
    .header-cell {
      background-color: #F7F7F7 !important;
      border-bottom: 1px solid #E9E9E9 !important;
      border-right: 1px solid #E9E9E9 !important;
    }
    
    #fm-pivot-view .fm-grid-layout div.fm-cell {
      padding-left: 20px;
    }
    
    #fm-pivot-view .fm-header {
      background-color: #e9e9e9 !important;
      border-right: 1px solid #d5d5d5 !important;
      border-bottom: 1px solid #d5d5d5 !important;
    }
    
    .fm-updated-cell-down {
      color: #DF3800 !important;
      font-weight: bold !important;
      background-image: none !important;
      -webkit-animation: fadeIt 5s ease-in-out;
      -moz-animation: fadeIt 5s ease-in-out;
      -o-animation: fadeIt 5s ease-in-out;
      animation: fadeIt 5s ease-in-out;
    }
    
    .fm-updated-cell-down::before {
      content: "\2193 \00a0";
      position: relative;
      bottom: 2px;
    }
    
    .fm-updated-cell-up {
      color: #00A45A !important;
      font-weight: bold !important;
      background-image: none !important;
      -webkit-animation: fadeIt1 5s ease-in-out;
      -moz-animation: fadeIt1 5s ease-in-out;
      -o-animation: fadeIt1 5s ease-in-out;
      animation: fadeIt1 5s ease-in-out;
    }
    
    .fm-updated-cell-up::before {
      content: '\2191 \00a0';
      position: relative;
      bottom: 2px;
    }
    
    @-webkit-keyframes fadeIt {
      0% {
        background-color: #FFFFFF;
      }
    
      20% {
        background-color: #F9D7CC;
        border-bottom: 1px solid #e9c5ba;
        border-right: 1px solid #e9c5ba;
      }
    
      50% {
        background-color: #F9D7CC;
        border-bottom: 1px solid #e9c5ba;
        border-right: 1px solid #e9c5ba;
      }
    
      100% {
        background-color: #FFFFFF;
      }
    }
    
    @-moz-keyframes fadeIt {
      0% {
        background-color: #FFFFFF;
      }
    
      20% {
        background-color: #F9D7CC;
        border-bottom: 1px solid #e9c5ba;
        border-right: 1px solid #e9c5ba;
      }
    
      50% {
        background-color: #F9D7CC;
        border-bottom: 1px solid #e9c5ba;
        border-right: 1px solid #e9c5ba;
      }
    
      100% {
        background-color: #FFFFFF;
      }
    }
    
    @-o-keyframes fadeIt {
      0% {
        background-color: #FFFFFF;
      }
    
      20% {
        background-color: #F9D7CC;
        border-bottom: 1px solid #e9c5ba;
        border-right: 1px solid #e9c5ba;
      }
    
      50% {
        background-color: #F9D7CC;
        border-bottom: 1px solid #e9c5ba;
        border-right: 1px solid #e9c5ba;
      }
    
      100% {
        background-color: #FFFFFF;
      }
    }
    
    @keyframes fadeIt {
      0% {
        background-color: #FFFFFF;
      }
    
      20% {
        background-color: #F9D7CC;
        border-bottom: 1px solid #e9c5ba;
        border-right: 1px solid #e9c5ba;
      }
    
      50% {
        background-color: #F9D7CC;
        border-bottom: 1px solid #e9c5ba;
        border-right: 1px solid #e9c5ba;
      }
    
      100% {
        background-color: #FFFFFF;
      }
    }
    
    @-webkit-keyframes fadeIt1 {
      0% {
        background-color: #FFFFFF;
      }
    
      20% {
        background-color: #CCEDDE;
        border-bottom: 1px solid #aedbc7;
        border-right: 1px solid #aedbc7;
      }
    
      50% {
        background-color: #CCEDDE;
        border-bottom: 1px solid #aedbc7;
        border-right: 1px solid #aedbc7;
      }
    
      100% {
        background-color: #FFFFFF;
      }
    }
    
    @-moz-keyframes fadeIt1 {
      0% {
        background-color: #FFFFFF;
      }
    
      20% {
        background-color: #CCEDDE;
        border-bottom: 1px solid #aedbc7;
        border-right: 1px solid #aedbc7;
      }
    
      50% {
        background-color: #CCEDDE;
        border-bottom: 1px solid #aedbc7;
        border-right: 1px solid #aedbc7;
      }
    
      100% {
        background-color: #FFFFFF;
      }
    }
    
    @-o-keyframes fadeIt1 {
      0% {
        background-color: #FFFFFF;
      }
    
      20% {
        background-color: #CCEDDE;
        border-bottom: 1px solid #aedbc7;
        border-right: 1px solid #aedbc7;
      }
    
      50% {
        background-color: #CCEDDE;
        border-bottom: 1px solid #aedbc7;
        border-right: 1px solid #aedbc7;
      }
    
      100% {
        background-color: #FFFFFF;
      }
    }
    
    @keyframes fadeIt1 {
      0% {
        background-color: #FFFFFF;
      }
    
      20% {
        background-color: #CCEDDE;
        border-bottom: 1px solid #aedbc7;
        border-right: 1px solid #aedbc7;
      }
    
      50% {
        background-color: #CCEDDE;
        border-bottom: 1px solid #aedbc7;
        border-right: 1px solid #aedbc7;
      }
    
      100% {
        background-color: #FFFFFF;
      }
    }
    

    This demo illustrates how to apply the conditional formatting feature to the data updated on the fly.

    With one API call, updateData(), you can update the data source and keep the same slice and formatting. This approach accelerates data loading speed by eliminating reloading the report.