Other Section multiselect option refreshing the other section chart data.

2 Answers 39 Views
Charts MultiSelect
Mahesh
Top achievements
Rank 1
Iron
Mahesh asked on 13 Oct 2023, 02:01 PM | edited on 13 Oct 2023, 03:53 PM

The multi-select is placed outside of the chart component. The change of multi-select chart data is refreshing which ideally shouldn't be.


BasicGroupChart.js /* Use this for simple charts with the following type: - bar - column - area - line */ import * as React from 'react'; import { Chart, ChartTitle, ChartSubtitle, ChartSeries, ChartSeriesItem, ChartCategoryAxis, ChartCategoryAxisItem, ChartLegend, ChartLegendTitle, ChartTooltip, ChartAxisDefaults } from '@progress/kendo-react-charts'; import { IntlProvider } from "@progress/kendo-react-intl"; import 'hammerjs'; import { groupBy } from "@progress/kendo-data-query"; import { dateFormat } from '@insight/toolkit-react'; export const BasicGroupedChart = (props) => { //set variables from properties passed const chartType = props.chartType; // area, line, bar, column, etc const title = props.title; // chart title const subTitle = props.subTitle; //chart subtitle const data = props.data; //chart data const groupedByField = props.groupedByField; //field used for legend keys const valueField = props.valueField; // field for values (y axis) const categoryField = props.categoryField; // field for categories (x axis) const valueFormat = props.valueFormat; // format for values in y axis (ex. c0 for currency no decimals and p for percent) const labelFormat = props.labelFormat; // format for labels (ex c2 for currency with decimals, n0 for number, no decimals) const showLabels = props.showLabels; //shows or hides value labels const categoryTitle =props.categoryTitle; // title for the Category axis const legendPosition = props.legendPosition; //position of the legend, top, right, bottom, etc const legendTitle = props.legendTitle; //title of the legend const tooltipFormat = props.tooltipFormat; // format for tooltip (ex "My tooltip {0:c}") const locale = props.locale; // culture local (ex. "en-GB") const showCategoryLabels = props.showCategoryLabels; // show the category axis labels const legendVisible = props.legendVisible ?? true; const stacked = props.stacked ?? false; //const colorField = props.colorField ?? "" //alert("DATA = " + JSON.stringify(data)); const series = groupBy(data, [ { field: groupedByField, }, ]); const mapSeries = (item, idx) => ( <ChartSeriesItem key={idx} data={item.items} name={item.value} field={valueField} categoryField={categoryField} type={chartType} labels={{visible:showLabels, format: labelFormat}} stack={stacked} //colorField={colorField} /> ); return( <IntlProvider locale={locale}><Chart><ChartLegend visible={legendVisible} position={legendPosition}><ChartLegendTitle text={legendTitle}></ChartLegendTitle></ChartLegend><ChartTitle text={title} /><ChartSubtitle text={subTitle} /><ChartCategoryAxis><ChartCategoryAxisItem title={{text: categoryTitle}} labels={{visible: showCategoryLabels}} /></ChartCategoryAxis><ChartAxisDefaults labels={{ format: valueFormat }} /><ChartTooltip format={tooltipFormat} /><ChartSeries> {series.map(mapSeries)} {/*props.series.map(s => <ChartSeriesItem name={s.name} data={s.data} key={s.name} type="area"/>)*/} </ChartSeries></Chart></IntlProvider> ); }; Component Used - <BasicGroupedChart chartType="column" title="Invoice Breakdown by Product Category" subTitle="" data={spendPeriod?.spend ? spendPeriod?.spend : ""} categoryField="group" valueField="value" groupedByField="label" categoryTitle="" legendPosition="bottom" legendTitle="" legendVisible={false} tooltipFormat="{0:c}" showLabels={true} valueFormat="c2" labelFormat="c2" locale={accountInfo?.locale} ></BasicGroupedChart>Multi Select - import { DropDownList, MultiSelect } from "@progress/kendo-react-dropdowns"; <MultiSelect data={productNameData} textField="label" dataItemKey="value" value={productName} name="msCategory" placeholder="All" onChange={handleProductNameChange} /> const handleProductNameChange = (event) => { setProductName(event.value); setProductNameObject([...event.value]); setProductNameLength(event.value.length) };

 

 

Created one dummy Project -

https://stackblitz.com/edit/react-ab4fou-czgxv7?file=index.js

Multi select change, delete should not impact the chart.


 

 

2 Answers, 1 is accepted

Sort by
0
Filip
Telerik team
answered on 17 Oct 2023, 12:24 PM

Hi, Mahesh,

The refresh that occurs after the user selects an item in the MultiSelect can be fixed by using the onRefresh event to prevent it. I updated the provided example with this approach:

https://stackblitz.com/edit/react-ab4fou-g5gasd?file=app%2Fchart.jsx

This way the Chart will not refresh if the MultiSelect changes a value.

Regards,
Filip
Progress Telerik

Stay tuned by visiting our public roadmap and feedback portal pages! Or perhaps, if you are new to our Kendo family, check out our getting started resources!

Mahesh
Top achievements
Rank 1
Iron
commented on 17 Oct 2023, 03:38 PM | edited

I tried with my current project and it's not working as expected.

Created one common code for chart BasicGroupChart.js

and from the other pages calling this common code. On the change of 

handleProductNameChange

setting the value to false as well.

 

Calling from normal file - 

import React, { useEffect, useState, useRef } from 'react';
import request from "../../library/api/request";
import { useRecoilState, useRecoilValue } from 'recoil';
import { selectedAccountState } from '../../recoil/userAtoms';
import { billableItemsGridState, billableItemsSortState  } from '../../recoil/pageAtoms';
import { Panel } from '@insight/toolkit-react';
import GridFunctions from '../../common/gridFunctions';
import { BasicGroupedChart } from "../Charts/BasicGroupedChart.js";
import "./AzurePlan.css";
import "../../common/override.scss";
import { IntlProvider } from "@progress/kendo-react-intl";
import { filterBy } from "@progress/kendo-data-query";
import { CurrencyFormatter } from "./../Localization/CurrencyFormatter.js";
import { DropDownList, MultiSelect } from "@progress/kendo-react-dropdowns";
import { azureInvoiceColumns } from '../../common/commonDataSets';
import { Button } from '@progress/kendo-react-buttons';
import { selectedDateState } from '../../recoil/pageAtoms';
import { Skeleton } from "@progress/kendo-react-indicators";
import GridTable from '../../../xps-utils/core/GridTable';
import { ProductsLoader, gridPagination } from "../../common/products-loader";
import { gridResponse } from "../../recoil/gridAtoms";
import {
  Chart,
  ChartArea,
  ChartSeries,
  ChartSeriesItem,
} from '@progress/kendo-react-charts';

//initial grid sort
const initialSort = [
  {
    field: "invoiceDate",
    dir: "desc",
  },
];

const columns = azureInvoiceColumns;

export default function AzureInvoiceComponent() {
  const accountInfo = useRecoilValue(selectedAccountState);
  const gridDetails = useRecoilValue(gridResponse);
  const [gridData, setGridData] = useRecoilState(billableItemsGridState);
  const [gridSort, setGridSort] = useRecoilState(billableItemsSortState);
  //use Grid Functions for resizing the grids
  const { setInitialColumnWidth, setWidth } = GridFunctions();
  const [dateSelected, setDate] = useRecoilState(selectedDateState);
  const [spendPeriod, setSpendPeriod] = useState([]);
  const [selectedMonth, setSelectedMonth] = useState();
  const [selectLists, setSelectLists] = useState([]);
  const [productName, setProductName] = useState([]);
  const [subscriptionID, setSubscriptionID] = useState([]);
  const [subscriptionName, setSubscriptionName] = useState([]);
  const [invoiceMonthDetail, setInvoiceMonthDetail] = useState([]);
  const [totalInvoiceMonthDetail, setTotalInvoiceMonthDetail] = useState([]);
  const [invoiceTrendData, setInvoiceTrendData] = useState([]);
  const [initialInvoiceMonth, setInitialInvoiceMonth] = useState([]);
  const [usageMonth, setUsageMonth] = useState();
  const [initialLoading, setInitialLoading] = useState(true);
  const [customLoading, setCustomLoading] = useState(false);
  const [detailLoading, setDetailLoading] = useState(false);
  const [productNameObject, setProductNameObject] = useState([]);
  const [subscriptionIDObject, setSubscriptionIDObject] = useState([]);
  const [subscriptionNameObject, setSubscriptionNameObject] = useState([]);
  const [page, setPage] = useState(0);
  const [filterQuery, setFilterQuery] = useState();
  const [isButtonDisabled, setIsButtonDisabled] = useState(true);
  const [showNotifiedText, setShowNotifiedText] = useState(false);
  const [productNameLength, setProductNameLength] = useState(0);
  const [subscriptionIDLength, setSubscriptionIDLength] = useState(0);
  const [subscriptionNameLength, setSubscriptionNameLength] = useState(0);
  const [applyFilterClicked, setApplyFilterClicked] = useState(false);
  const [refreshChart, setRefreshChart] = useState(true);


  const handleChartRefresh = (chartOptions, themeOptions, chartInstance) => {
    setRefreshChart(false);
  };
  
 
  const handleProductNameChange = (event) => {
    setProductName(event.value);
    setProductNameObject([...event.value]);
    setProductNameLength(event.value.length);
    setRefreshChart(false);
  };


  return (
    <IntlProvider locale="en-US">
      <div className="main_content_container">
        <div className="c-container">
          <div className="o-grid o-grid--gutters-tiny">
            <div className="o-grid__item u-1/1 dashboard-items">
              <Panel>
                <Panel.Body>
                  {initialLoading ? (
                    <Skeleton
                      shape={"text"}
                      style={{
                        width: "15%",
                        height: 50,
                      }}
                    />
                  ) : (
                    <div className="header-text-large">Azure Plan Invoice</div>
                  )}
                  <div className="o-grid o-grid--gutters">
                    <div className="o-grid__item u-1/4">
                      {initialLoading ? (
                        <Skeleton
                          shape={"rectangle"}
                          style={{
                            width: "100%",
                            height: 50,
                          }}
                        />
                      ) : (
                        <>
                          <span className="label-text-bold">Invoice Month</span>
                          <DropDownList
                            data={initialInvoiceMonth}
                            textField="text"
                            dataItemKey="value"
                            value={selectedMonth}
                            onChange={dateChange}
                            style={{
                              width: "100%",
                              float: "right",
                            }}
                          />
                        </>
                      )}
                    </div>
                    <div className="o-grid__item u-1/2">&nbsp;</div>
                    <div className="o-grid__item u-1/4">
                      {initialLoading || customLoading ? (
                        <Skeleton
                          shape={"rectangle"}
                          style={{
                            width: "100%",
                            height: 50,
                          }}
                        />
                      ) : (
                        <>
                          <div className="right pad-right">
                            <span className="label-text-bold">
                              Invoice Total
                            </span>
                            <div className="invoice-total-text">
                              <CurrencyFormatter
                                value={spendPeriod?.totalSpend}
                                alignRight={true}
                              />
                            </div>
                          </div>
                        </>
                      )}
                    </div>

                    <div className="o-grid__item u-1/2">
                      {initialLoading || customLoading ? (
                        <Skeleton
                          shape={"rectangle"}
                          style={{
                            width: "100%",
                            height: "auto",
                            minHeight: 400,
                            marginTop: 10,
                          }}
                        />
                      ) : (
                        <BasicGroupedChart
                          chartType="column"
                          title="Invoice Breakdown by Product Category"
                          subTitle=""
                          data={spendPeriod?.spend ? spendPeriod?.spend : ""}
                          categoryField="label"
                          valueField="value"
                          groupedByField="group"
                          categoryTitle=""
                          legendPosition="bottom"
                          legendTitle=""
                          legendVisible={false}
                          tooltipFormat="{0:c}"
                          showLabels={true}
                          valueFormat="c2"
                          labelFormat="c2"
                          locale={accountInfo?.locale}
                          handleChartRefresh={handleChartRefresh}
                           ></BasicGroupedChart>
                      )}
                    </div>
                    <div className="o-grid__item u-1/2">
                      {initialLoading || customLoading ? (
                        <Skeleton
                          shape={"rectangle"}
                          style={{
                            width: "100%",
                            height: "auto",
                            minHeight: 400,
                            marginTop: 10,
                          }}
                        />
                      ) : (
                        <BasicGroupedChart
                          chartType="column"
                          title="Trending 6 Month Spend"
                          subTitle=""
                          data={invoiceTrendData}
                          categoryField="group"
                          valueField="value"
                          groupedByField="label"
                          categoryTitle=""
                          legendPosition="bottom"
                          legendTitle=""
                          tooltipFormat="{0:c}"
                          showLabels={false}
                          valueFormat="c2"
                          labelFormat="c2"
                          stacked={true}
                          locale={accountInfo?.locale}
                        ></BasicGroupedChart>
                      )}
                    </div>
                  </div>
                </Panel.Body>
              </Panel>
            </div>
          </div>
          <div className="o-grid o-grid--gutters-tiny">
            <div className="o-grid__item u-1/1 dashboard-items">
              <Panel>
                <Panel.Body>
                  <div className="o-grid o-grid--gutters">
                    <div className="o-grid__item u-1/5">
                      {initialLoading || customLoading ? (
                        <Skeleton
                          shape={"rectangle"}
                          style={{
                            width: "100%",
                            height: 50,
                            marginTop: 20,
                          }}
                        />
                      ) : (
                        <>
                          <span className="label-text-bold">
                            Product Category
                          </span>
                          <MultiSelect
                            data={productNameData}
                            textField="label"
                            dataItemKey="value"
                            value={productName}
                            name="msCategory"
                            placeholder="All"
                            onChange={handleProductNameChange}
                          />
                        </>
                      )}
                    </div>
                    <div className="o-grid__item u-1/5">
                      {initialLoading || customLoading ? (
                        <Skeleton
                          shape={"rectangle"}
                          style={{
                            width: "100%",
                            height: 50,
                            marginTop: 20,
                          }}
                        />
                      ) : (
                        <>
                          <span className="label-text-bold">Product Name</span>
                          <MultiSelect
                            data={productNameData}
                            textField="label"
                            dataItemKey="value"
                            value={productName}
                            name="msProducts"
                            placeholder="All"
                            onChange={handleProductNameChange}
                          />
                        </>
                      )}
                    </div>
                    <div className="o-grid__item u-1/5">
                      {initialLoading || customLoading ? (
                        <Skeleton
                          shape={"rectangle"}
                          style={{
                            width: "100%",
                            height: 50,
                            marginTop: 20,
                          }}
                        />
                      ) : (
                        <>
                          <span className="label-text-bold">
                            Subscription ID
                          </span>
                          <MultiSelect
                            data={subscriptionIdData}
                            textField="label"
                            dataItemKey="value"
                            value={subscriptionID}
                            name="msSubscriptions"
                            placeholder="All"
                            onChange={handleSubscriptionIDChange}
                          />
                        </>
                      )}
                    </div>
                    <div className="o-grid__item u-1/5">
                      {initialLoading || customLoading ? (
                        <Skeleton
                          shape={"rectangle"}
                          style={{
                            width: "100%",
                            height: 50,
                            marginTop: 20,
                          }}
                        />
                      ) : (
                        <>
                          <span className="label-text-bold">
                            Subscription Name
                          </span>
                          <MultiSelect
                            data={subscriptionNameData}
                            textField="label"
                            dataItemKey="value"
                            value={subscriptionName}
                            name="msInvoices"
                            placeholder="All"
                            onChange={handleSubscriptionNameChange}
                          />
                        </>
                      )}
                    </div>

                    <div className="o-grid__item u-1/5 apply-button">
                      {initialLoading || customLoading ? (
                        <Skeleton
                          shape={"rectangle"}
                          style={{
                            width: "100%",
                            height: 50,
                            marginTop: -3,
                          }}
                        />
                      ) : (
                        <>
                          <Button
                            themeColor={"primary"}
                            onClick={handleApplyFilter}
                            disabled={isButtonDisabled ? true : false}
                          >
                            Apply Filters
                          </Button>
                          &nbsp;
                          <Button icon="import" onClick={excelExport}>
                            Download
                          </Button>
                        </>
                      )}
                    </div>
                    <div className="o-grid__item u-1/1">
                      <div
                        className={`apply-button-text  ${
                          showNotifiedText ? "" : "hide"
                        }`}
                        id="apply-button-message"
                      >
                        <span className="k-icon k-i-information"></span>
                        &nbsp;Selected filters have not been applied. Please
                        click the "Apply Fitlers" button to change your search.
                      </div>
                    </div>
                  </div>

                  <div className="o-grid o-grid--gutters">
                    <div className="o-grid__item u-1/2"></div>
                    <div className="o-grid__item u-1/1">
                      <div className="billable_item_grid">
                        {initialLoading || customLoading || detailLoading ? (
                          <Skeleton
                            shape={"rectangle"}
                            style={{
                              width: "100%",
                              height: 50,
                              marginTop: -3,
                            }}
                          />
                        ) : (
                          <>
                            <GridTable
                              name={"azureInvoice"}
                              columns={columns}
                              _export={_export}
                              gridSort={gridSort}
                              filterable={true}
                              sortable={true}
                              pageable={true}
                              dataState={{ ...dataState }}
                              data={products}
                              gridData={gridDetails?.content}
                              page={page}
                              dataStateChange={dataStateChange}
                              setWidth={setWidth}
                            />
                            <ProductsLoader
                              page={page}
                              apiEndPoint={"invoiceMonthDetail"}
                              usageMonth={usageMonth}
                              filterQuery={filterQuery}
                              dataState={dataState}
                              onDataReceived={dataReceived}
                            />
                          </>
                        )}
                      </div>
                    </div>
                  </div>
                </Panel.Body>
              </Panel>
            </div>
          </div>
        </div>
      </div>
    </IntlProvider>
  );
}

 

Updated BasicGroupChartFIle - 

/*
  Use this for simple charts with the following type:
    - bar
    - column
    - area
    - line
*/

import React from 'react';
import {
  Chart,
  ChartTitle,
  ChartSubtitle,
  ChartSeries,
  ChartSeriesItem,
  ChartCategoryAxis,
  ChartCategoryAxisItem,
  ChartLegend,
  ChartLegendTitle,
  ChartTooltip,
  ChartAxisDefaults,
} from "@progress/kendo-react-charts";
import { IntlProvider } from "@progress/kendo-react-intl";
import "hammerjs";
import { groupBy } from "@progress/kendo-data-query";
import { dateFormat } from "@insight/toolkit-react";

export const BasicGroupedChart = (props) => {
  //set variables from properties passed
  const chartType = props.chartType; // area, line, bar, column, etc
  const title = props.title; // chart title
  const subTitle = props.subTitle; //chart subtitle
  const data = props.data; //chart data
  const groupedByField = props.groupedByField; //field used for legend keys
  const valueField = props.valueField; // field for values (y axis)
  const categoryField = props.categoryField; // field for categories (x axis)
  const valueFormat = props.valueFormat; // format for values in y axis (ex. c0 for currency no decimals and p for percent)
  const labelFormat = props.labelFormat; // format for labels (ex c2 for currency with decimals, n0 for number, no decimals)
  const showLabels = props.showLabels; //shows or hides value labels
  const categoryTitle = props.categoryTitle; // title for the Category axis
  const legendPosition = props.legendPosition; //position of the legend, top, right, bottom, etc
  const legendTitle = props.legendTitle; //title of the legend
  const tooltipFormat = props.tooltipFormat; // format for tooltip (ex "My tooltip {0:c}")
  const locale = props.locale; // culture local (ex. "en-GB")
  const showCategoryLabels = props.showCategoryLabels; // show the category axis labels
  const legendVisible = props.legendVisible ?? true;
  const stacked = props.stacked ?? false;
  const handleChartRefresh = props?.handleChartRefresh;
  console.log('handleChartRefresh -> ', handleChartRefresh);

  //const colorField = props.colorField ?? ""

  //alert("DATA = " + JSON.stringify(data));

  const series = groupBy(data, [
    {
      field: groupedByField,
    },
  ]);
  const mapSeries = (item, idx) => (
    <ChartSeriesItem
      key={idx}
      data={item.items}
      name={item.value}
      field={valueField}
      categoryField={categoryField}
      type={chartType}
      labels={{ visible: showLabels, format: labelFormat }}
      stack={stacked}
      //colorField={colorField}
    />
  );
  return (
    <IntlProvider locale={locale}>
      <Chart onRefresh={handleChartRefresh}>
        <ChartLegend visible={legendVisible} position={legendPosition}>
          <ChartLegendTitle text={legendTitle}></ChartLegendTitle>
        </ChartLegend>
        <ChartTitle text={title} />
        <ChartSubtitle text={subTitle} />
        <ChartCategoryAxis>
          <ChartCategoryAxisItem
            title={{ text: categoryTitle }}
            labels={{ visible: showCategoryLabels }}
          />
        </ChartCategoryAxis>
        <ChartAxisDefaults
          labels={{
            format: valueFormat,
          }}
        />
        <ChartTooltip format={tooltipFormat} />

        <ChartSeries>
          {series.map(mapSeries)}
          {/* props.series.map(s => <ChartSeriesItem name={s.name} data={s.data} key={s.name} type="area"/>) */}
        </ChartSeries>
      </Chart>
    </IntlProvider>
  );
};

The chart itself not loading.


0
Mahesh
Top achievements
Rank 1
Iron
answered on 18 Oct 2023, 07:03 PM

I found the solution.

From the page just pass the chart elements to the base chart file.

onRefresh should pass in the same way.


 <Chart onRefresh={handleChartRefresh}>
              <BasicChart
                chartType="column"
                title="Subscriptions Expiring"
                subTitle=""
                data={spendTrend}
                categoryField="group"
                valueField="value"
                groupedByField="label"
                legendPosition="bottom"
                legendTitle="Months to Expiration"
                tooltipFormat="{0:n}"
                showLabels={false}
                labelFormat="n"
                stacked={false}
                // colorField="#AE0A46"
              ></BasicChart>
            </Chart>

Filip
Telerik team
commented on 19 Oct 2023, 12:04 PM

Hi, Mahesh,

I am glad to hear that you have found a working solution.

Let us know in case further assistance is needed and the issue resurfaces.

Regards,
Filip
Mahesh
Top achievements
Rank 1
Iron
commented on 19 Oct 2023, 12:06 PM

Filip
Telerik team
commented on 23 Oct 2023, 10:12 AM

Hi, Mahesh,

It seems that my colleague has already answered it. You can continue the discussion there.

Regards,
Filip
Tags
Charts MultiSelect
Asked by
Mahesh
Top achievements
Rank 1
Iron
Answers by
Filip
Telerik team
Mahesh
Top achievements
Rank 1
Iron
Share this question
or