How can I access nested object and render it to datatable? - reactjs

How can I render the user_id information under the product array? I'm trying to render the nested information of user_id such as the username
The DataGrid is working successfully since I render all non-nested information or
non-populated info. But I'm also trying to show the information under user_id
{field: "user_id", headerName: "User Name", width: 250,}
this is the field I used, but it's not working since user_id is an object
Edit
Sample
This is what I received
Datagrid.js
<div className="datatable">
<DataGrid
className="datagrid"
rows={list}
getRowId={(row) => row._id}
columns={columns.concat(actionColumn)}
pageSize={9}
rowsPerPageOptions={[9]}
checkboxSelection
/>
</div>

So you will have to use renderCell() => ReactElement property and return the nested object string. I've updated your code sandbox with the solution and it is now rendering the username correctly.
Below is the code that I've modified in your code sandbox.
{
field: "user_id",
headerName: "User Name",
width: 250,
renderCell: (params) => {
return params.row.user_id.username;
},
},
Here is the link to documentation that you may want to go through.

Related

nextJs ServerSideProps and rendering the HTML for SEO

Here is the issue I am having. I am trying to have the Ag-grid render it's html output using NextJS getServerSideProps. However, when I view the source code, it doesn't appear to have any of the HTML rendered for SEO purposes. If I go ahead and output the "staff" array to a div then the HTML output is viewable in the source code so at least I know the function is working. Is there something I need to do to have AGGridReact render its contents?
export default function Home({ staff }) {
const gridRef = useRef();
const defaultColDef = {
resizable: true,
sortable: true,
};
const [columnDefs] = useState([
{ headerName: 'First Name', field: 'first_name' },
{ headerName: 'Last Name', field: 'last_name' },
{ headerName: 'Job Title', field: 'job_title' },
{ field: 'office' },
{ field: 'email' },
{ field: 'phone' },
]);
return (
<>
<main>
<div style={{ height: '600px' }}>
<AgGridReact
id='staff_grid'
ref={gridRef}
rowData={staff}
defaultColDef={defaultColDef}
columnDefs={columnDefs}
rowSelection={'single'}
style={{ height: '100%', width: '100%' }}
></AgGridReact>
</div>
</main>
</>
);
}
// This gets called on every request
export async function getServerSideProps() {
const staff = [];
for (let id = 1; id <= 3; id++) {
staff.push({
id: id,
first_name: 'first' + id,
last_name: 'last' + id,
email: 'member' + id + '#company.com',
phone: '12345' + id,
office: 'place' + id,
job_title: 'Worker ' + id,
});
}
// Pass data to the page via props
return { props: { staff } };
}
TLDR: Diving deep into the ag-grid's node_modules abyss and into their documentation, I found that their grid component is being injected into the DOM (client-side) once an "AG Grid" wrapper component has been mounted. Therefore, this is a client-side only component.
Debugging
When I request the Next page from Postman, I see an empty div where the grid should be:
But when I request the page from the browser, I see the grid:
An even easier way to determine that this is a client-side only component would be to assign the grid a debug prop:
<AgGridReact
debug
rowData={staff}
columnDefs={columnDefs}
rowSelection="single"
/>
We see AG Grid debug logs in the browser (Notice the Rendered on Client message):
But, we don't see any AG Grid debug logs on the server (Notice the Rendered on Server message):
More investigation
I thought I found a server-side rendering solution via their Row Models, but unfortunately it's not referring to the table being SSR'd, but the data being lazy loaded via dynamically fetching data from a server. My guess as to why this table is client-side only is that AG Grid doesn't use a native table, but instead a bunch of div elements with custom styles to represent a table. Since the server doesn't have a DOM (eg, can't access document nor window), calculating these dynamic styles wouldn't be possible.
Alternatives
If you're creating this table for an enterprise and it's absolutely vital to have this page SSR'd for SEO, then I'd recommend having some sort of bot detection in Next's middleware and within gSSP. Then pass an isBot prop to the component and conditionally render a native table (styling won't matter since it's mainly used for SEO). We do something similar for our web application where search results need to be baked into the page on the server, but can be lazy-loaded client-side for a snappier UX.
Here's a working demo. You can change the User-Agent using your browser's tools or by changing it within the request headers.
A more comprehensive bot list can be found here.
What a user sees:
What a bot sees:

How to add extra components to DataGrid row MUI

I'm trying to add extra components to a row in a MUI DataGrid.
For example, in the DataGrid below, I want to add some text below the main contents of a row. (Notice row ID 5's First name column's value)
Is there an API available that allows for this kind of modification without having to modify the core components? If not, how can I create a customized component that allows for this behavior?
Sandbox example
You can use the renderCell property in the field. Inside the return you can write you component like you would do normaly.
const columns = [
{ field: "id", headerName: "ID", width: 90 },
{
field: "firstName",
headerName: "First name",
width: 150,
editable: true,
renderCell: (params) => {
return (
<Stack>
<span>{params.value}</span>
<span>Your extra text</span>
</Stack>
);
}
},
...
]
Here is the working codesandbox based on your code

Disable alphabetical sorting in ag-grid using the basic model

I use server side sorting with ag-grid. So far I used the enableServerSideSorting property set to true. But after version upgrade this property is not available.
I use the onSortChanged event to capture the sort state of the grid. And I want to handle this sorting on the server side. So ag-grid only display the data in the original order as it comes from the server. Now I sort the data outside the grid and then ag-grid sorting again alphabetically.
I created an example for this. There are two component property setSortParams where I set the sorting and data where I get the data already sorted.
How can I prevent the double sorting?
const ExternalGrid = ({ data, setSortParams }) => {
const gridOptions = {
columnDefs: [
{
headerName: "Quantity",
field: "quantity",
sortable: true
}
],
defaultColDef: {
sortable: true
}
};
const onSortChanged = params => {
const sortModel = params.api.getSortModel();
setSortParams([
sortModel.length > 0,
sortModel.length > 0 ? sortModel[0].sort === "desc" : false
]);
};
return (
<div
className="ag-theme-balham"
style={{
height: "180px",
width: "300px"
}}
>
<AgGridReact
gridOptions={gridOptions}
modules={AllCommunityModules}
onSortChanged={onSortChanged}
rowData={data}
/>
</div>
);
};
example: https://codesandbox.io/s/ag-grid-server-side-sorting-chy7j
You can see in the example, that I display the data under the table. My goal is that it has the same order in the table whatever order I set clicking on the table header.
if you implement the following comparator in every column definition, the grid will not modify the row order when it sorts:
columnDefs: [
{
headerName: "Quantity",
field: "quantity",
sortable: true,
comparator: (valueA, valueB, nodeA, nodeB, isInverted) => 0
}
],
https://codesandbox.io/s/ag-grid-server-side-sorting-fmmgf
While working with server side row model, you should not assign the rowData directly (rowData={data}). Instead, create ServerSideDatasource. When you sort on any column, you will be able to get details as parameters for getRows method.
You could use it to provide sorting info to the server.
Reference: Implementing the Server-side Datasource
Have a look at this plunk: https://plnkr.co/edit/z8KzsZ8sAcCe9tYWJedS?p=preview.
When you sort on a column, observe that you get the details by params.request.sortModel inside dataSource.getRows method.
[{
colId: "athlete"
sort: "asc"
}]

CXJS - How to get the record.id from link onclick within the Gridcell

I am still learning things on both react and cxjs. I am trying to develop a lookup widget which pops a window with a grid and the user can search and select an entry from that.
I want to use a Link within cxjs grid cell and when clicking the link I need to call a controller method with id of that particular row (record.id). Below is what I have tried with no success.
.....
style="max-width: 500px; width: 500px; max-height:500px;"
border={false}
columns={[
{
field: 'name', sortable: true,
items: <cx>
<Link onClick={(e, ins) => {
ins.store.set("$lookup.selText", e.? /* can I use e to get id and set it to store */);
ins.controller.selectRecord("{$record.id}"); // this doesn't work either
ins.parentOptions.dismiss();
}} text-tpl="{$record.name}"/>
</cx>,
header: {
style: 'width: 150px',
items: 'Name'
},
},
Could someone please shed some lights?
Thanks,
Priyanga
You can get the value from the store using the get function.
store.get("$record.id")

exportDataAsCsv is not supported property or method of gridOptions.api

According to AG-Grid docs here there is a method on the gridOptions.api that allows data export of the table contents. However, whenever I run the function, I simply get the error Object doesn't support property or method 'exportDataAsCsv'.
It's running in a directive that looks a little like this:
app.directive('myDirective', function() {
restrict: 'E',
template-url: "blah.html",
link:{pre: function(scope,ele){
var columnDefs = [
{ headerName: "Management Name", field: "ManagementName", width: 300 },
{ headerName: "Location", field: "Location", width: 150 },
{ headerName: "Backend System", field: "Vendor", width: 110 },
{ headerName: "Total Active Sites", field: "TotalActiveSites", width: 110 }
];
scope.gridOptions = { columnDefs: columnDefs, rowData: null }
},
post: function (scope,ele) {
scope.exportCsv = function() { scope.gridOptions.api.exportDataAsCsv(); }
scope.gridOptions.rowData = dataList;
scope.gridOptions.api.onNewRows();
}
And my html looks like this:
<input placeholder="Filter..." type="text" ng-model="gridOptions.quickFilterText" />
<button ng-click="exportCsv()">
<img id="btnExportToExcel" alt="CSV File" src="../images/Excel.gif" style="cursor:pointer;" tooltip-placement="bottom" uib-tooltip="Excel" />
</button>
<div ag-grid="gridOptions" class="ag-blue" style="height:100%"></div>
The grid runs fine, but for some reason it doesn't believe that this method exists. Any ideas on why that might be? I'm using version 1.12 of ag-grid. I'm assuming my references are all good, or else I wouldn't get a grid to show at all.
exportDataAsCsv() wasn't introduced until version 2.0. You'll need to upgrade to a newer version of ag-grid which is now at v5.x.
If you're absolutely stuck with v1.12, it shouldn't be too hard to write your own CSV data exporter.
Here's a proof of concept on JSFiddle that converts JSON data to CSV format and exports it so the user can save it. To use this, you'll just need to give it the data from the ag-grid (or from your own data model that you supplied to ag-grid in the first place).
Export ag-grid data as CSV

Resources