EasyUI Forum
February 07, 2023, 11:47:17 PM *
Welcome, Guest. Please login or register.

Login with username, password and session length
News:
 
   Home   Help Search Login Register  
Pages: [1]
  Print  
Author Topic: DataGrid dynamic column order rendering different  (Read 646 times)
chrwei
Full Member
***
Posts: 219


View Profile Email
« on: November 28, 2022, 03:19:07 PM »

This example is simplified from my actual use, but represents the pattern.  My Pre and Post functions have a lot more logic.

When you change to type C you can see the column order displayed does not match the column array.

Code:
import './App.css';
import { useState } from 'react';
import { ComboBox, DataGrid, GridColumn, LinkButton } from 'rc-easyui';

function App() {

  const [myData, setData] = useState({
    hasopt2: false,
    info: [
      { title: "Item 1", opt1: 50, opt2: 0, opt3: "Thing 1", opt3e: 25 },
      { title: "Item 2", opt1: 75, opt2: 0, opt3: "Thing 2", opt3e: 45 },
    ],
    selected: {}
  });

  const [currentType, setType] = useState("");
  const [gridCols, setGridCols] = useState([]);


  function ColPre(coltype) {
    let cols = [
      <GridColumn key={"a1"} field="title" title=" " width={140} />,
    ];
    switch (coltype) {
      case "C":
        cols.push(<GridColumn key={"a2"} field="opt1" title={"Option 1"} width={65} />);
        break;
      default: break;
    }
    return cols;
  }

  function ColPost(coltype) {
    function onSelPrice(row) {
      let newdata = { ...myData };
      if (coltype === "C") {
        newdata.selected = {
          title: row.title,
          opt3: row.opt3,
          opt3e: row.opt3e,
        };
      } else {
        newdata.selected = {
          title: row.title,
          opt3: row.opt3,
        };
      }
      setData(newdata);
    }

    let cols = [];
    switch (coltype) {
      case "C":
        cols.push(<GridColumn key={"c1"} field="opt3e" title={"Option 3 X"} width={80} />);
        break;
      default: break;
    }

    cols.push(<GridColumn key={"c2"} field="select" title=" " width={45} render={({ row }) => (<LinkButton onClick={() => onSelPrice(row)}>Use</LinkButton>)} />);
    return cols;
  }

  function GetCols(coltype) {
    return [
      ...ColPre(coltype),
      <GridColumn field="opt2" title={"Option 2"} hidden={!myData.hasopt2} width={65} />,
      <GridColumn field="opt3" title={"Option 3"} />,
      ...ColPost(coltype),
    ];
  }

  return (
    <div className="App">
      <ComboBox value={currentType}
        data={[
          { value: "A", text: "Type A" },
          { value: "B", text: "Type B" },
          { value: "C", text: "Type C" },
        ]}
        onSelectionChange={selection => {
          setType(selection.value);
          setGridCols(GetCols(selection.value));
        }}
      >
      </ComboBox>
      <DataGrid
        style={{ maxHeight: 150, width: 600 }}
        data={myData.info}
      >
        {gridCols}
      </DataGrid>
      Selected: {JSON.stringify(myData.selected)}<br />
      Cols: <pre>{JSON.stringify(gridCols, null, 2)}</pre>
    </div>
  );
}

export default App;

I haven't tried putting every possible column in and using the hidden property, I think that code would be rather cumbersome.

Is there some way to force it to re-render correctly?
   
Logged
jarry
Administrator
Hero Member
*****
Posts: 2178


View Profile Email
« Reply #1 on: November 28, 2022, 04:14:11 PM »

You have the same 'key' though you change to another column. Please remove the 'key' property, or set it with a different value.
Code:
  function ColPre(coltype) {
    let cols = [
      <GridColumn field="title" title=" " width={140} />,
    ];
    switch (coltype) {
      case "C":
        cols.push(<GridColumn field="opt1" title={"Option 1"} width={65} />);
        break;
      default: break;
    }
    return cols;
  }
Logged
chrwei
Full Member
***
Posts: 219


View Profile Email
« Reply #2 on: November 29, 2022, 07:19:20 AM »

in my real project not having key gives errors about needing keys.

in this test it doesn't error, but it also behaves even worse, the use button is in 2 columns
Logged
chrwei
Full Member
***
Posts: 219


View Profile Email
« Reply #3 on: November 29, 2022, 07:39:38 AM »

this does work, using a ref to make sure each render gets new indexes. though I'm not sure if this will cause issues long term.  the page won't be that long lived, so probably OK in this use case.



Code:
import './App.css';
import { useRef, useState } from 'react';
import { ComboBox, DataGrid, GridColumn, LinkButton } from 'rc-easyui';

function App() {
  const refColIdx = useRef(1);

  const [myData, setData] = useState({
    hasopt2: false,
    info: [
      { title: "Item 1", opt1: 50, opt2: 0, opt3: "Thing 1", opt3e: 25 },
      { title: "Item 2", opt1: 75, opt2: 0, opt3: "Thing 2", opt3e: 45 },
    ],
    selected: {}
  });

  const [currentType, setType] = useState("");
  const [gridCols, setGridCols] = useState([]);


  function ColPre(coltype) {
    let cols = [
      <GridColumn key={refColIdx.current++} field="title" title=" " width={140} />,
    ];
    switch (coltype) {
      case "C":
        cols.push(<GridColumn key={refColIdx.current++} field="opt1" title={"Option 1"} width={65} />);
        break;
      default: break;
    }
    return cols;
  }

  function ColPost(coltype) {
    function onSelPrice(row) {
      let newdata = { ...myData };
      if (coltype === "C") {
        newdata.selected = {
          title: row.title,
          opt3: row.opt3,
          opt3e: row.opt3e,
        };
      } else {
        newdata.selected = {
          title: row.title,
          opt3: row.opt3,
        };
      }
      setData(newdata);
    }

    let cols = [];
    switch (coltype) {
      case "C":
        cols.push(<GridColumn key={refColIdx.current++} field="opt3e" title={"Option 3 X"} width={80} />);
        break;
      default: break;
    }

    cols.push(<GridColumn key={refColIdx.current++} field="select" title=" " width={45} render={({ row }) => (<LinkButton onClick={() => onSelPrice(row)}>Use</LinkButton>)} />);
    return cols;
  }

  function GetCols(coltype) {
    return [
      ...ColPre(coltype),
      <GridColumn key={refColIdx.current++} field="opt2" title={"Option 2"} hidden={!myData.hasopt2} width={65} />,
      <GridColumn key={refColIdx.current++} field="opt3" title={"Option 3"} />,
      ...ColPost(coltype),
    ];
  }

  return (
    <div className="App">
      <ComboBox value={currentType}
        data={[
          { value: "A", text: "Type A" },
          { value: "B", text: "Type B" },
          { value: "C", text: "Type C" },
        ]}
        onSelectionChange={selection => {
          setType(selection.value);
          setGridCols(GetCols(selection.value));
        }}
      >
      </ComboBox>
      <DataGrid
        style={{ maxHeight: 150, width: 600 }}
        data={myData.info}
      >
        {gridCols}
      </DataGrid>
      ColIdx: {refColIdx.current} Selected: {JSON.stringify(myData.selected)}<br />
      Cols: <pre>{JSON.stringify(gridCols, null, 2)}</pre>
    </div>
  );
}

export default App;
Logged
Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines Valid XHTML 1.0! Valid CSS!