Hi,
I'm struggling to wire up a grid to an existing restful service using hooks (rather than classes, as the examples do). The closest I have gotten is wrap the grid jsx in a conditional, based on the data load; which to me is a bit ugly. Seems like I should be able to watch the data and update as needed.
Looking forward, I'd like to swap to GraphQL.
The problem is, I am having a hell of a time finding examples on any of this. Everything in the docs is pre-hooks, oData based. As we are running MEAN stack, oData is out of the picture for us.
10 Answers, 1 is accepted
By way of example, the following code is ignoring the column config (and this is the previously mentioned conditional):
const Logging = () => {
const [data, setData] = useState([]);
useEffect(() => {
const fetchLogs = async () => {
await getLogs()
.then((logs) => loadLogs(logs));
};
fetchLogs();
}, []);
const loadLogs = (logs) => {
setData(logs);
};
return
(
<>
{data.length ? (
<>
<Grid
style={{ height:
'420px'
}}
sortable
data={data}
total={data.length}
/>
<GridColumn field=
"app_id"
title=
"app id"
/>
<GridColumn field=
"app_name"
title=
"app name"
/>
<GridColumn field=
"app_version"
title=
"version"
/>
<GridColumn field=
"created_on"
title=
"created"
format=
"{0:d}"
/>
<GridColumn field=
"id"
title=
"id"
/>
<GridColumn field=
"message"
title=
"message"
/>
<GridColumn field=
"type"
title=
"type"
/>
<GridColumn field=
"updated_on"
title=
"updated"
format=
"{0:d}"
/>
</>
) :
null
}
</>
);
};
Currently, we have separate examples with hooks and with GraphQL, but they are separate ones:
1) Hooks:
https://www.telerik.com/kendo-react-ui/components/integration/nextjs/
2) GraphQL:
- Grid with editing:
https://www.telerik.com/kendo-react-ui/components/integration/graphql/
- Homepage demo:
https://github.com/telerik/kendo-react-homepage-demo/
If these example do not prove helpful, please let me know and I will try to create a small example with KendoReact Grid using hooks and GraphQL.
-----------------------------------------------
As a side note, our new documentation site is written with GatsbyJS, GraphQL, hooks and our components work nice in this stack.
Regards,
Stefan
Progress Telerik
Hi Stefan,
thanks for the reply. It turns out, I was making a pretty simple error. If you note the markup in my code example, I was not nesting the <GridColumn> in the <Grid>; once I made that change, everything was working perfectly.
The thing is, I was getting no errors and no feedback, so I kept looking elsewhere for the issue and assumed it might have something to do with how I was trying to bind the data. I'm pretty new to both React and Kendo so this was a novice mistake :)
Hi Stefan,
I have progressed on and now am using GraphQL, Hooks and Apollo. I was able to connect it quiet easily to the data, but now I am floundering on enabling paging/sorting, etc.
My query (through Apollo) looks like this:
const LOGS_QUERY = gql`
query Logs($skip: Int, $first: Int) {
logs (skip: $skip, first: $first) {
id,
app_id,
app_name,
app_version,
type,
message,
created_on,
updated_on
}
}
`;
Thank you for the code.
This can be achived by usitizing the onDataStateChange or the onPageChange(if the Grid has only paging) events:
https://www.telerik.com/kendo-react-ui/components/grid/api/GridProps/#toc-ondatastatechange
https://www.telerik.com/kendo-react-ui/components/grid/api/GridProps/#toc-onpagechange
These events will contain the needed information for the request, skip and take.
Then the requested data from the request has to be passed to the Grid.
Regards,
Stefan
Progress Telerik
Thanks for the response Stephan,
I did try to use both of those event hooks, in many different setups, but haven't had any success. It seems that wrapping the <Grid> component with the Apollo <Query> component, is break things. Doing this, I am not able to get the pageChange event to fire.
I'd prefer to use the Apollo library, as it is quite popular and easy to use. This is my first time using React + GraphQL + Kendo, any suggestions?
const pageChange = (e) => {
console.log(e); // this never fires!
};
return (
<
Query
query={LOGS_QUERY}
variables={{
skip: 0,
first: 5
}}
fetchPolicy
=
"cache-and-network"
notifyOnNetworkStatusChange={true}
>
{({ loading, data, fetchMore }) => (
loading
? <
Spinner
/>
: <
Grid
className
=
"logs mt-4"
data={data.logs || []}
pageable
sortable
onPageChange={pageChange}
>
<
GridColumn
field
=
"app_id"
title
=
"App Id"
/>
<
GridColumn
field
=
"app_name"
title
=
"App Name"
/>
<
GridColumn
field
=
"type"
title
=
"Message Type"
/>
<
GridColumn
field
=
"message"
cell={MessageCell}
title
=
"Message"
/>
<
GridColumn
field
=
"created_on"
cell={DateCell}
title
=
"Created"
/>
<
GridColumn
field
=
"updated_on"
cell={DateCell}
title
=
"Updated"
/>
</
Grid
>
)}
</
Query
>
)
};
Stefan,
const Logging = () => {
const [dataState, setDataState] = useState({ skip: 0, take: 10 });
/**
* Grid dataStateChange Event Curry
* - curry the fetchMore function for future consumption
* @param {*} fetchMore - Apollo paging fetch function
* @return {function} - dataStateChange Event handler
*/
const dataStateChangeCurry = (fetchMore) => {
/**
* Grid dataStateChange Event handler
* @param {Event} e - dataStateChange Event
* @return {Promise} - curried function fetchMore Promise
*/
const dataStateChange = (e) => {
setDataState(e.data); // update the dataState with e.skip/take
return fetchMore({
variables: {
skip: e.data.skip,
first: e.data.take
},
updateQuery: (prev, { fetchMoreResult }) => {
return fetchMoreResult
? Object.assign({}, {
logs: [...fetchMoreResult.logs]
})
: prev;
}
});
};
return dataStateChange;
};
return (
<
Query
query={LOGS_QUERY}
variables={{
skip: 0,
first: 10
}}
fetchPolicy
=
"cache-and-network"
notifyOnNetworkStatusChange={true}
>
{({ loading, data, fetchMore }) => (
<
React.Fragment
>
<
Grid
className
=
"logs mt-4"
data={data.logs || []}
total={30}
pageable
sortable
{...dataState}
onDataStateChange={dataStateChangeCurry(fetchMore)}
>
<
GridColumn
field
=
"app_id"
title
=
"App Id"
/>
<
GridColumn
field
=
"app_name"
title
=
"App Name"
/>
<
GridColumn
field
=
"type"
title
=
"Message Type"
/>
<
GridColumn
field
=
"message"
cell={MessageCell}
title
=
"Message"
/>
<
GridColumn
field
=
"created_on"
cell={DateCell}
title
=
"Created"
/>
<
GridColumn
field
=
"updated_on"
cell={DateCell}
title
=
"Updated"
/>
</
Grid
>
{loading && <
Spinner
/>}
</
React.Fragment
>
)}
</
Query
>
)
};
I was finally able to get the paging working. Please take a look and point out any obvious issues you might see.
Thanks in advance!
I'm glad to hear that the paging is working successfully.
Based on the provided code everything regarding the Grid seems correct.
The only thing that I noticed is that the total is set to a fix number(30). When the data is coming from the server we recommend to get that value from the server as well, as the total on the server may be different.
Regards,
Stefan
Progress Telerik
Thanks Stefan,
I should have mentioned that. We didn't have total's coming through yet, so I was just hard-coding while developing. I will update that, of course, when the totals is available.
BTW, I ended up stumbling on react-hooks-apollo, and went that route instead. I found it made the code much cleaner.
Just putting it here in case someone else has a similar question (and the total is still hard-coded!).
import React, { useState } from
'react'
;
import { Grid, GridColumn } from
'@progress/kendo-react-grid'
;
import { LOGS_QUERY } from
'../../queries/queries'
;
import { useQuery } from
'react-apollo-hooks'
;
import Spinner from
'../shared/spinner/Spinner'
;
import DateCell from
'../shared/data-cell/DateCell'
;
import MessageCell from
'../shared/message-cell/MessageCell'
;
/**
* Logging Component
* - displays logs using Kendo Grid and Apollo Query
*/
const Logging = () => {
/**
* Default grid state
*/
const [dataState, setDataState,] = useState({ skip: 0, take: 10 });
/**
* Default query variables
*/
const variables = { skip: 0, first: 10, };
/**
* Logs Query hook
*/
const { data, error, loading, fetchMore, } = useQuery(LOGS_QUERY, { variables });
/**
* Grid dataStateChange Event handler
*
* @param {Event} e - dataStateChange Event
* @return {Promise} - curried function fetchMore Promise
*/
const dataStateChange = (e) => {
const { filter, skip, sort, take } = e.data;
setDataState({ filter, skip, sort, take });
return
fetchMore({
variables: {
skip,
orderBy: sort
? sort.map((item) => `${item.field}_${item.dir.toUpperCase()}`)
: []
},
updateQuery: (prev, { fetchMoreResult }) => {
return
fetchMoreResult
? Object.assign({}, { logs: [...fetchMoreResult.logs] })
: prev;
}
});
};
// query error
if
(error) {
return
(
<React.Fragment>
{`<p>Error: ${error}</p>`}
</React.Fragment>
);
};
// render spinner while query runs
if
(loading) {
return
(
<Spinner />
);
};
// render grid
return
(
<React.Fragment>
<h2 className=
"text-primary"
>Logging</h2>
<hr />
<Grid
style={{ height:
"625px"
}}
data={data.logs || []}
total={30}
filterable
pageable
sortable
{...dataState}
onDataStateChange={dataStateChange}
>
<GridColumn field=
"app_id"
title=
"App Id"
/>
<GridColumn field=
"app_name"
title=
"App Name"
/>
<GridColumn field=
"type"
title=
"Message Type"
/>
<GridColumn field=
"message"
cell={MessageCell} title=
"Message"
/>
<GridColumn field=
"created_on"
cell={DateCell} title=
"Created"
/>
<GridColumn field=
"updated_on"
cell={DateCell} title=
"Updated"
/>
</Grid>
</React.Fragment>
)
};
export { Logging as
default
};
Thank you for sharing the code with the community.
We always appreciate sharing examples that can be helpful.
I have added some Telerik points to your account for sharing it.
Regards,
Stefan
Progress Telerik