How to disable a specific row to be draggable in AG table? - reactjs

I am using the Managed Dragging of AG Grid React table and want to disable a specific row, if it matches the condition.
In Docs I couldn't find enough information how to do that. As it describes here, it is possible to add the draggable feature conditionally, like this
rowDrag: params => !params.node.group
In params object, I couldn't find the row data to implement my condition.
In the code example described below, I want to disable the row to be draggable if the name==='John.
Also, how to that if you have row draggable for entire row: rowDragEntireRow={true}?
Sandbox demo and code
import React from "react";
import { AgGridReact } from "ag-grid-react";
import "ag-grid-community/dist/styles/ag-grid.css";
import "ag-grid-community/dist/styles/ag-theme-alpine.css";
function App() {
const [gridApi, setGridApi] = React.useState(null);
const [gridColumnApi, setGridColumnApi] = React.useState(null);
const onGridReady = (params) => {
setGridApi(params.api);
setGridColumnApi(params.columnApi);
};
const defaultColDef = {
flex: 1,
editable: true
};
const columnDefs = [
{
headerName: "Name",
field: "name",
rowDrag: (params) => {
console.log("params", params);
return !params.node.group;
}
},
{ headerName: "stop", field: "stop" },
{
headerName: "duration",
field: "duration"
}
];
const rowData = React.useMemo(
() => [
{
name: "John",
stop: 10,
duration: 5
},
{
name: "David",
stop: 15,
duration: 8
},
{
name: "Dan",
stop: 20,
duration: 6
}
],
[]
);
return (
<div>
<h1 align="center">React-App</h1>
<div>
<div className="ag-theme-alpine" style={{ height: "700px" }}>
<AgGridReact
columnDefs={columnDefs}
rowData={rowData}
defaultColDef={defaultColDef}
onGridReady={onGridReady}
rowDragManaged={true}
//rowDragEntireRow={true}
></AgGridReact>
</div>
</div>
</div>
);
}
export default App;
Any help will be appreciated

Update your rowDrag definition in the name column definition to the following:
rowDrag: (params) => {
if (params.data.name == "John") {
return false;
}
return true;
}
Demo.

Related

How to grab data from selected row in React MUI Data-Grid table with Axios

I am trying to use the example here to add the selectedRow functionality from #mui/x-data-grid to return all the data form a selected row. In the demo, they are using the useDemoData mod to populate the table, whereas I am using Axios to make a call to my API to populate the rows and using preconfigured columns.
import React, { useState, useEffect } from 'react';
import axios from "axios";
import { DataGrid, GridToolbar } from '#mui/x-data-grid';
const columns = [
{ field: 'id', headerName: 'Job ID', width: 170 },
{ field: 'file_name', headerName: 'File Name', width: 250 },
{ field: 'product_type', headerName: 'Product Type', width: 300 },
{ field: 'status', headerName: 'Status', width: 170, editable: true },
];
function QueueMgrTable() {
const [data, setData] = useState([]);
const [loadingData, setLoadingData] = useState(true);
const [selectedRows, setSelectedRows] = useState([]);
async function getData() {
await axios
.get('https://myendpoint.com/test/jobs', {
headers: {
'Content-Type': 'application/json'
}
})
.then((response) =>{
var test_data = response.data.data;
setData(
test_data.map((x) => {
return {
id: parseInt(`${x.job_id}`),
file_name: `${x.file_name}`,
product_type: `${x.product_type}`,
status: `${x.status}`
}
})
);
setLoadingData(false);
});
}
useEffect((data) => {
console.log(config);
getData();
if (loadingData) {
getData();
}
}, []);
return (
<div style={{ height: 600, width: '100%' }}>
{loadingData ? (
<p>Loading. Please wait...</p>
) : (
<DataGrid
columns={columns}
pageSize={20}
rowsPerPageOptions={[10]}
checkboxSelection
components={{ Toolbar: GridToolbar }}
onSelectionModelChange={(ids) => {
const selectedIDs = new Set(ids);
const selectedRows = data.rows.filter((row) =>
selectedIDs.has(row.id),
);
setSelectedRows(selectedRows);
}}
rows={data}
/>
)}
<pre style={{ fontSize: 10 }}>
{JSON.stringify(selectedRows, null, 4)}
</pre>
</div>
);
};
export default QueueMgrTable;
When I click on a row in the above, I get the following error. Any suggestions or clues as to what I am doing wrong here? I suspect that it trying to use filter when the data is undefined for some reason due to state.
To resolve this issue, I had to make a few simple changes to the following block of code. First, I changed const to let. Then I had to remove the rows from data.rows.filter((row) ... as it was undefined. The data object is already defined as an array, and therefore, I can use the filter method to find the correct "row" data based on the id.
onSelectionModelChange={(ids) => {
let selectedIDs = new Set(ids);
let selectedRows = data.filter((row) =>
selectedIDs.has(row.id),
);
setSelectedRows(selectedRows);
}}
This resolved the error issue and allowed me to properly define selectedIDs.

Material-UI v5 DataGridPro Highlight First Row Upon Load

I am loading a really basic grid using DataGridPro and I need the top row to be selected and highlighted upon loading. I did not see a great example when I tried researching.
This is what my DataGridPro component looks like:
Here is what I have so far:
<DataGridPro
disableMultipleSelection={true}
columns={[
{
field: "startDate",
headerName: "Start Date",
description: "start.",
type: "date",
valueFormatter: ({ value }) => dateFormatter(value),
flex: 0.5,
},
{
field: "endDate",
headerName: "End Date",
description: "end.",
type: "date",
valueFormatter: ({ value }) => (value !== null ? dateFormatter(value) : null),
flex: 0.5,
},
]}
rows={data ? data : null}
></DataGridPro>
I'm not sure what to do since I can't find any examples in their demos or API documentation.
The example that gets you closest to what you want is the Controlled selection example. That example demonstrates how to hold the selection in state and pass it as a prop to the data grid. The example does not include how to change the selection from outside the data grid.
The main thing you need to know is that the selectionModel prop is an array of the selected row ids, so to have the first row start as selected, you need to pass in an array with that row id.
Below is a modified version of the example from the documentation that demonstrates selecting the first row.
import * as React from "react";
import { DataGrid } from "#mui/x-data-grid";
import { useDemoData } from "#mui/x-data-grid-generator";
export default function ControlledSelectionGrid() {
const { data, loading } = useDemoData({
dataSet: "Commodity",
rowLength: 10,
maxColumns: 6
});
const [selectionModel, setSelectionModel] = React.useState([]);
const dataRef = React.useRef(data);
React.useEffect(() => {
// The ref allows me to leave `data` out of the dependency array
// of the next effect, so that it is only triggered by changes
// to the `loading` state.
dataRef.current = data;
});
React.useEffect(() => {
if (!loading) {
const { rows } = dataRef.current;
if (rows.length > 0) {
setSelectionModel([rows[0].id]);
}
}
}, [loading]);
return (
<div style={{ height: 400, width: "100%" }}>
<DataGrid
checkboxSelection
onSelectionModelChange={(newSelectionModel) => {
setSelectionModel(newSelectionModel);
}}
selectionModel={selectionModel}
{...data}
/>
</div>
);
}
There is some extra complexity in the above code due to useDemoData loading the data asynchronously. Depending on how your data is passed to the data grid, you may be able to avoid the useEffect calls and simplify this to something like the following:
import * as React from "react";
import { DataGrid } from "#mui/x-data-grid";
export default function ControlledSelectionGrid({ data }) {
const [selectionModel, setSelectionModel] = React.useState(() => {
const { rows } = data;
const initialSelectionModel = [];
if (rows.length > 0) {
initialSelectionModel.push(rows[0].id);
}
return initialSelectionModel;
});
return (
<div style={{ height: 400, width: "100%" }}>
<DataGrid
checkboxSelection
onSelectionModelChange={(newSelectionModel) => {
setSelectionModel(newSelectionModel);
}}
selectionModel={selectionModel}
{...data}
/>
</div>
);
}

React Filter and Map data for Datagrid returning no values

I suspect it is a syntax issue. When I use the same approach for instead of I do get the expected results. The data is coming from an endpoint through the import of getAssembly which is generated via await fetch and the results are being rendered as JSON before the data is imported.
The commented out code on line how I assume the commanded need to be executed and I get no error, but no data is rendered. The code on line 50 works fine but does not provide the filtering. I intend the use the value in the typeName variable once the filtering is working.
import { useState, useEffect } from "react";
import MenuItem from "#mui/material/MenuItem";
import Select from "#mui/material/Select";
import InputLabel from "#mui/material/InputLabel";
import ListItemText from "#mui/material/ListItemText";
import { DataGrid } from "#mui/x-data-grid";
import { getAssembly } from "./GetAssembly";
const columns = [
{ field: "id", headerName: "ID", width: 300 },
{ field: "status", headerName: "Status", width: 90 },
{ field: "atype", headerName: "AType", width: 80 },
{ field: "name", headerName: "Name", width: 350 },
{ field: "time", headerName: "Start Time", width: 150 },
{ field: "org", headerName: "Organization", width: 350 },
];
export default function SelectAssembly() {
const [typeName, setTypeName] = useState([""]);
// const [assemRows, setAssemRows] = useState([]);
const [state, setState] = useState({
assembly: [],
assembtypename: [],
unsignenList: [],
});
const handleTypeChange = (event) => {
const {
target: { value },
} = event;
setTypeName(value);
};
console.log(typeName);
useEffect(() => {
console.log("useEffect");
getAssembly().then((res) => {
setState((prevState) => ({ ...prevState, assembly: res.assemblies }));
});
}, []);
const typeSelection = [
...new Set(state.assembly.map((item) => item.assemblyType)),
];
//const assemList = state.assembly.filter(assem => assem === "batch").map(assem => {
const assemList = state.assembly.map((assem) => {
return {
id: assem.assemblyId,
status: assem.status,
atype: assem.assemblyType,
name: assem.name,
time: assem.timeStarted,
org: assem.organizationId,
asid: assem.referenceId,
pmap: assem.propertiesMap,
};
});
// const unsignedList = assemList.filter((str) => {
// //str can include or str can equal with === (return str.includes("import");)
// return str === "import";
// });
return (
<div>
<InputLabel sx={{ fontSize: 12 }}>Assembly Type</InputLabel>
<Select
label="Type"
value={typeName}
sx={{ height: 35, fontSize: 10 }}
fullWidth
focused
onChange={handleTypeChange}
>
{typeSelection.map((types) => {
return (
<MenuItem key={types.indexOf(types) > -1} value={types}>
<ListItemText primary={types} />
</MenuItem>
);
})}
</Select>
<br />
<br />
<DataGrid
density="compact"
hideFooterRowCount
rows={assemList}
// rows={unsignedList}
columns={columns}
pageSize={15}
rowsPerPageOptions={[15]}
/>
</div>
);
}
Thanks to Jim Ptak at Southwire for helping me see the problem. In the filter method I did not specify the particular element to filter on. Once the code was modified as follows:
const assemList = state.assembly.filter(assem => assem.assemblyType === "MO import").map(assem => {
//const assemList = state.assembly.map((assem) => {
return {
id: assem.assemblyId,
status: assem.status,
atype: assem.assemblyType,
name: assem.name,
time: assem.timeStarted,
org: assem.organizationId,
asid: assem.referenceId,
pmap: assem.propertiesMap,
};
});
the contents of the datagrid filters perfectly.

How can I maintain the datagrid checkbox of the material ui in local storage?

I am facing one problem while using material ui.
const [selectedRows, setSelectedRows] = useState([]);
useEffect(() => {
localStorage.setItem('row_selected', JSON.stringify(selectedRows));
}, [selectedRows]);
// return
<DataGrid
components={{
NoRowsOverlay: NoRows,
Toolbar: GridToolbar,
}}
rows={tableData}
columns={columns}
checkboxSelection
selectionModel={JSON.parse(localStorage.getItem('row_selected'))}
onSelectionModelChange={setSelectedRows}
hideFooterPagination
/>
I'm using the checkbox function of datagrid, and even if I refresh the page, I'm saving it in local storage to maintain the checked.
However, the problem is that local storage is also reset because the new value is reset every refresh.
How can I keep it refreshed?
I saw this example enter link description here, but I think it's different from the new value problem that automatically reset every refresh.
You can use this code I've created ... I tested it and it works good
import * as React from "react";
import { DataGridPro } from "#mui/x-data-grid-pro";
export default function DataGridProDemo() {
const [selectionModelItems, setSelectionModel] = React.useState([]);
React.useEffect(() => {
const parsedArrayFromLocalStorage = JSON.parse(localStorage?.getItem("SelectedOption") || "[]");
const mappedArray = parsedArrayFromLocalStorage.map(item => {
return item;
}, [selectionModelItems]);
console.log("log", mappedArray);
setSelectionModel(mappedArray);
}, []);
console.log("selectionModelItems from outsource is : ", selectionModelItems);
return (
<div style={{ height: 520, width: "100%" }}>
<DataGridPro
columns={[
{ field: 'default', width: 150 },
{ field: 'name', width: 150 },
{ field: 'stars', width: 150 },
]}
rows={[
{
id: 1,
name: 'MUI',
stars: 28000,
default: 'Open source',
},
{
id: 2,
name: 'DataGridPro',
stars: 15000,
default: 'Enterprise',
},
]}
rowHeight={38}
checkboxSelection
disableSelectionOnClick
onSelectionModelChange={(ids) => {
// ids is array of seleced rows
console.log("ids is : ", ids);
setSelectionModel(ids);
// i made this condtion because onSelectionModelChange called after each render of the component and without this conditon storage will be empty every refresh
if (ids.length > 0) {
localStorage.setItem("SelectedOption", JSON.stringify(ids));
}
}}
selectionModel={selectionModelItems ? selectionModelItems : []}
/>
</div>
);
}

Display data in antd table based on selected item from select option

I need to display data on the antd table based on the selected item from select option.The data that are to be displayed are stored in different variables. For example, if school is selected from select option then the datasource is available in schoolData and similarly for other option.
Here's my code:
import React, { useState } from "react";
import Framework from "../framework/Framework";
import { Dropdown, Button, Table, message, Select } from "antd";
import { DeleteOutlined, DownOutlined, EditOutlined } from "#ant-design/icons";
import { Content } from "antd/lib/layout/layout";
import AddNewButton from "../addNewButton/AddNewButton";
import "./attributes.css";
import DataSource from "./Datasource";
import IconDescription from "../icondescription/IconDescription";
import Modal from "antd/lib/modal/Modal";
import { Option } from "antd/lib/mentions";
const Attributes = () => {
const [page, setPage] = useState(1);
const [isModalVisible, setIsModalVisible] = useState(false)
// const [layer, setLayer] = useState()
const columns = [
{
title: "S.N",
dataIndex: "key",
},
{
title: "Name",
dataIndex: "name",
key: "name",
// render: (text) => <a>{text}</a>,
},
{
title: "Address",
dataIndex: "address",
key: "address",
},
{
title: "Contact No.",
dataIndex: "contactno",
key: "contactno",
},
{
title: "Operation",
dataIndex: "operation",
key: "operation",
render: () => {
return (
<div style={{ display: "flex" }}>
<IconDescription icon={<EditOutlined />} label="Edit" />
<IconDescription icon={<DeleteOutlined />} label="Delete" />
</div>
);
},
},
];
const addAttribute = () => {
setIsModalVisible(true)
}
const modalHandleOk = () => {
setIsModalVisible(false);
};
const modalHandleCancel = () => {
setIsModalVisible(false);
};
const selectLayer = (e) => {
console.log("select layer", e)
}
return (
<Framework>
<Content className="attributes">
<div className="select-addNewBtn-container">
<Select defaultValue="school" style={{ width: 120 }} onChange={selectLayer}>
<Option value="school">School</Option>
<Option value="hospital">Hospital</Option>
<Option value="policeStation">Police Station</Option>
</Select>
<AddNewButton name={"Add New Attribute"} addNewBtn={addAttribute} />
<Modal title={"Add New Attribute"} visible={isModalVisible} centered onCancel={modalHandleCancel} onOk={modalHandleOk}>
</Modal>
</div>
<Table
dataSource={DataSource}
columns={columns}
className="data-table"
pagination={{
size: "small",
pageSize: 6,
hideOnSinglePage: true,
showSizeChanger: false,
}}
/>
</Content>
</Framework>
);
};
export default Attributes;
How do i achieve the desired functionality? Do let me know. Quite a beginner at such things.
Assuming Datasource is just a simple array of data objects, and presumably you have another file eg: 'SchoolData' that you need to switch between when the select option is chosen.
What I'd do to keep it simple is create a react state variable to wrap your data and just set it at will in the onChange of your select.
Example

Resources