sample Image that I want to achiveSo the problem is I'm using devextreme components for my react applications. In building this special page I got struct with a special case in devextreme UI case. I have a row containing headers two lines of headers. first line is the fixed line of headerson top of table containing shed, storagetype,assignedbags,capacity, maxbags, lead,bagsper layer. the second line containing rendering header below to the shed and storagetype, they are location and comment. So when I press the button to add the location should add the new row. I tryed to perform the same thing but I'm getting the single line row. Please help me
import React, { useState,useEffect } from "react";
import apis from "../api-constants";
import './temporarystack.scss';
import DataGrid, { Column } from "devextreme-react/data-grid";
import useGetAPI from "../getAPIS";
import { Button, SelectBox } from "devextreme-react";
import { formatMessage } from "devextreme/localization";
export default function TemporaryStack ({tokenDetails,operation,isTempUsed,temporaryStacksJSON}) {
const [showTable, setShowTable] = useState(false);
const [listData, setListData] = useState([]);
const [shedOptions, setShedOptions] = useState(null);
const [threshold,setThreshold]=useState({})
const storageTypeOptions=[
{id:1,name:'Gang Way'},
{id:2,name:'Alley Way'},
{id:3,name:'Road Side'},
{id:4,name:'Plinth'},
{id:5,name:'Others'}
]
useEffect(()=>{
async function Dataapi(){
const responceforshed=await useGetAPI(apis.GET_GODOWN_UNITS(operation))
const responceforthreshold=await useGetAPI(apis.GET_BAGWEIGHT_THRESHOLD_MAXIMUXBAGCAPACITY)
setShedOptions(responceforshed.data)
setThreshold(responceforthreshold.data)
}
if(showTable===true){
Dataapi()
}
},[operation,tokenDetails,showTable])
useEffect(()=>{
temporaryStacksJSON(listData)
},[listData])
// removing data when Temporary stack is unchecked and initialization state
const handleCheckboxChange = (e) => {
const isChecked = e.target.checked;
setShowTable(isChecked);
isTempUsed(isChecked)
if (!isChecked) {
setListData([])
}
};
// adding new row to the temporary stack
const addRow = () => {
const newItem = {
shed: shedOptions && shedOptions.length > 0 ? shedOptions[0]?.value : '',
storageType: storageTypeOptions.length > 0 ? storageTypeOptions[0].name : '',
assignedBags: '',
capacity: '',
maxBags: '',
lead: '',
bagsPerLayer: '',
locationDescription: '',
comment: '',
};
setListData((prevList) => [...prevList, newItem]);
};
// to delete a temporary stack
const deleteRow = (index) => {
const updatedList = [...listData];
updatedList.splice(index, 1);
setListData(updatedList);
};
// rendering the table or state change for data
const renderTable = () => {
if (!showTable) return null;
return (
<>
<DataGrid dataSource={listData} showBorders={true} style={{padding:0,margin:0}} className="table">
{/* column for selection of shed */}
<Column
width={25}
cellRender={record=>{
return(record.rowIndex+1)
}}/>
<Column
caption={formatMessage("Shed")}
width={100}
minWidth={80}
cellRender={(record) => (
<SelectBox
width={80}
dataSource={shedOptions}
displayExpr={'value'}
valueExpr={'value'}
onValueChange={e=>{
const updatedList = [...listData];
updatedList[record.rowIndex].shed = e;
setListData(updatedList);
}}
value={record.data.shed}
defaultValue={record.data.shed}
/>
)}
/>
{/* selection of storage type */}
<Column
width={100}
minWidth={80}
caption={formatMessage('StorageType')}
cellRender={(record) => (
<SelectBox
dataSource={storageTypeOptions}
displayExpr="name"
valueExpr="name"
onValueChanged={e=>{
const updatedList = [...listData];
updatedList[record.rowIndex].storageType = e.value;
setListData(updatedList);
}}
value={record.data.storageType}
defaultValue={record.data.storageType}
/>
)}
/>
<Column dataField="assignedBags" caption={formatMessage("AssignedBagInTemp")}
cellRender={(record) => (
<input
type="number"
defaultValue={record.data.assignedBags}
onBlur={(e) => {
const updatedList = [...listData];
updatedList[record.rowIndex].assignedBags=parseInt(e.target.value)
setListData(updatedList);
}}
onKeyDown={(e) => {
if (e.key === 'Enter') {
e.preventDefault();
}
}}
/>
)}/>
<Column dataField="capacity" caption={formatMessage('Capacity')}
cellRender={(record) => (
<input
type="number"
defaultValue={record.data.capacity}
onBlur={(e) => {
const updatedList = [...listData];
updatedList[record.rowIndex].capacity=parseInt(e.target.value)
setListData(updatedList);
}}
onKeyDown={(e) => {
if (e.key === 'Enter') {
e.preventDefault();
}
}}
/>
)}/>
<Column dataField="maxBags" caption={formatMessage('MaxBags')}
cellRender={(record) => (
<input
type="number"
defaultValue={record.data.maxBags}
onBlur={(e) => {
const updatedList = [...listData];
updatedList[record.rowIndex].maxBags=parseInt(e.target.value)
setListData(updatedList);
}}
onKeyDown={(e) => {
if (e.key === 'Enter') {
e.preventDefault();
}
}}
/>
)}/>
<Column dataField="lead" caption={formatMessage("Lead")}
cellRender={(record) => (
<input
type="number"
defaultValue={record.data.lead}
onBlur={(e) => {
const updatedList = [...listData];
updatedList[record.rowIndex].lead=parseInt(e.target.value)
setListData(updatedList);
}}
onKeyDown={(e) => {
if (e.key === 'Enter') {
e.preventDefault();
}
}}
/>
)}/>
<Column dataField="bagsPerLayer" caption={formatMessage('BagsPerLayer')}
cellRender={(record) => (
<input
type="number"
defaultValue={record.data.bagsPerLayer}
onBlur={(e) => {
const updatedList = [...listData];
updatedList[record.rowIndex].bagsPerLayer=parseInt(e.target.value)
setListData(updatedList);
}}
onKeyDown={(e) => {
if (e.key === 'Enter') {
e.preventDefault();
}
}}
/>
)}/>
<Column dataField="locationDescription" caption={formatMessage('LocationDescription')}
cellRender={(record) => (
<textarea
defaultValue={record.data.locationDescription}
onBlur={(e) => {
const updatedList = [...listData];
updatedList[record.rowIndex].locationDescription=e.target.value
setListData(updatedList);
}}
onKeyDown={(e) => {
if (e.key === 'Enter') {
e.preventDefault();
}
}}
/>
)}/>
<Column dataField="comment" caption={formatMessage('Commentl')}
cellRender={(record) => (
<textarea
defaultValue={record.data.comment}
onBlur={(e) => {
const updatedList = [...listData];
updatedList[record.rowIndex].comment=e.target.value
setListData(updatedList);
}}
onKeyDown={(e) => {
if (e.key === 'Enter') {
e.preventDefault();
}
}}
/>
)}/>
{/* column to delete the row */}
<Column
width={50}
cellRender={(cellData) => (
<Button
icon="close"
onClick={() => deleteRow(cellData.rowIndex)}
style={{borderRadius:'10%',backgroundColor:'rgba(249, 172, 156, 0.44)'}}
/>
)}
/>
</DataGrid>
<Button
icon="plus"
onClick={addRow}
style={{borderRadius:'10%',backgroundColor:'#c7ecc7',padding:0}}
/>
</>
);
};
return (
<>
<label>
<input type="checkbox" onChange={(e) => handleCheckboxChange(e)} />
{formatMessage('TemporaryStack')}
</label>
{renderTable()}
</>
);
};
I try to shift the column but haven't succeed
In DevExtreme, DataRow is a class representing a row in a data source, typically used within a data grid or similar components. When you refer to "datarowrender," you might be talking about customizing how these rows are rendered in a DevExtreme data grid.
In DevExtreme, you can customize the rendering of data rows using templates or through event handlers like onRowPrepared. Here's how you can customize the rendering of data rows:
Using Templates: DevExtreme provides templates that allow you to customize the appearance of various parts of the grid, including data rows. You can define a template for the data rows and specify the HTML and/or Angular/React/Vue components to render within each row. Here's an example of how you might define a data row template in DevExtreme:
<DataGrid
dataSource={dataSource}
onRowPrepared={handleRowPrepared}
>
<RowTemplate>
{(rowData, rowIndex) => (
<div className={rowIndex % 2 === 0 ? 'even-row' : 'odd-row'}>
{/* Custom rendering for each data row */}
<span>{rowData.name}</span>
<span>{rowData.age}</span>
</div>
)}
</RowTemplate>
</DataGrid>
Using Event Handlers: You can also use event handlers like onRowPrepared to customize the rendering of data rows dynamically. This event is triggered for each row before it is rendered, allowing you to modify its appearance based on data or other conditions. Here's an example:
dataSource={dataSource}
onRowPrepared={handleRowPrepared}
/>
and the function code is:
if (e.rowType === 'data') {
// Customize row appearance based on data
if (e.data.age < 18) {
e.rowElement.classList.add('minor-row');
} else {
e.rowElement.classList.add('adult-row');
}
}
}
caution:Since datarowrender is a type of function which render every time if there is a small change and cancels out if is used