I already parsing API using axios. After that I got the value then I adding to properties Data in Datatable but still not working. The value not parse to Datatable. When I console.log the data is showing. I am use API from https://jsonplaceholder.typicode.com/users.
And hear is my code:
import "./css/jquery.dataTables.css";
import React, { Component } from "react";
import axios from "axios";
const $ = require("jquery");
$.Datatable = require("datatables.net");
export default class Tbl extends Component {
constructor(props) {
super(props);
this.state = {
users: [],
loading: true,
};
}
//option 1
async getUsersData() {
const res = await axios.get("https://jsonplaceholder.typicode.com/users");
console.log(res.data);
this.setState({ loading: false, users: res.data });
}
//option 2
async getUsersData1() {
const res = await axios.get("https://jsonplaceholder.typicode.com/users");
return res.data;
}
componentDidMount() {
//call option 1
this.getUsersData();
this.$el = $(this.el);
this.$el.DataTable({
data: this.state.users, //option 1
data: this.getUsersData1(), //option 2
columns: [
{ title: "Name", data: "name" },
{ title: "Username", data: "username" },
{ title: "Email", data: "email" },
{ title: "Phone", data: "phone" },
{ title: "Website", data: "website" }
],
});
}
componentWillMount() {}
render() {
return (
<table className="display" width="100%"
ref={(el) => (this.el = el)}>
</table>
);
}
}
I already try for option 1 and option 2 but still not working.
Thank,
The problem I can see here is that you initialize the plugin table in incorrect way. In order to include DataTable plugin, you should call as require('datatables.net')(window, $). Then after you have done loading data, you just simply call sync data to table again. Here is the snippet:
const $ = require("jquery");
require("datatables.net")(window, $);
// Keep as you have done
async getUsersData() {
const res = await axios.get("https://jsonplaceholder.typicode.com/users");
console.log(res.data);
this.setState({ loading: false, users: res.data });
}
// Init table data as component is mounted
componentDidMount() {
this.getUsersData().then(() => this.syncTable());
}
// Split as new function to init the datatable
syncTable() {
this.$el = $(this.el);
this.$el.DataTable({
data: this.state.users, //option 1
// data: this.getUsersData1(), //option 2
columns: [
{ title: "Name", data: "name" },
{ title: "Username", data: "username" },
{ title: "Email", data: "email" },
{ title: "Phone", data: "phone" },
{ title: "Website", data: "website" }
]
});
}
Here is the codesandbox for you: https://codesandbox.io/s/gallant-faraday-e25mk?file=/src/App.js
Use the "react-data-table-component" library. It is the best library for the data table.
Run this command to install it
npm install react-data-table-component styled-components
Then you have to import it in the react component page and use it
import DataTable from 'react-data-table-component';
const data = [{ id: 1, title: 'DataTable in ReactJS', year: '2021' } ...];
const columns = [
{
name: 'Name',
selector: 'name',
sortable: true,
},
{
name: 'Username',
selector: 'username',
sortable: true,
},
{
name: 'Email',
selector: 'email',
sortable: true,
},
{
name: 'Phone',
selector: 'phone',
sortable: true,
},
{
name: 'Website',
selector: 'website',
sortable: true,
},
];
class MyComponent extends Component {
render() {
return (
<datatable title="YourBlogCoach" columns="{columns}" data="{data}">
</datatable>
)
}
};
Check here for tutorial
Related
I'm trying to populate an ag-grid component with data coming from a Vuex getter. The only remarkable thing to mention is that this data coming from the getter is asynchronous. When I debug the grid component I can see that the data from the getter is there but the rowData property from the grid is still empty and I get this error in the console:
This warning:
runtime-core.esm-bundler.js:38 [Vue warn]: Unhandled error during execution of mounted hook
at <Anonymous class="ag-theme-alpine" id="myGrid" columnDefs= {value: Array(7)} ... >
at
at <DesignSystem onVnodeUnmounted=fn ref=Ref< Proxy {callWebsocket: ƒ, sendMessage: ƒ, …} > >
at
at
at <ConfigProvider theme-overrides= {common: {…}, Checkbox: {…}, Radio: {…}, Button: {…}, Switch: {…}} theme=null >
at
This Error:
Uncaught (in promise) TypeError: this.gridOptions.columnDefs.forEach is not a function
at GridOptionsWrapper2.checkColumnDefProperties (ag-grid-community.cjs.js:18300:37)
at GridOptionsWrapper2.init (ag-grid-community.cjs.js:18240:18)
at ag-grid-community.cjs.js:1113:76
at Array.forEach ()
at Context2.callLifeCycleMethodsOnBean (ag-grid-community.cjs.js:1113:24)
at ag-grid-community.cjs.js:1096:70
at Array.forEach ()
at Context2.callLifeCycleMethods (ag-grid-community.cjs.js:1096:23)
at Context2.wireBeans (ag-grid-community.cjs.js:975:14)
at new Context2 (ag-grid-community.cjs.js:953:14)
Here's my component template:
<template>
<div class="test-container">
<ag-grid-vue
class="ag-theme-alpine"
id="myGrid"
:columnDefs="columnDefs"
domLayout="autoHeight"
unSortIcon="true"
#grid-ready="onGridReady"
:animateRows="true"
:rowData="rowData"
:defaultColDef="defaultColDef"
>
</ag-grid-vue>
</div>
</template>
And here's my setup function (I'm using Vue's 3 Composition API):
import { AgGridVue } from "ag-grid-vue3";
import { useActions, useGetters } from "vuex-composition-helpers";
import { reactive, onMounted, ref } from "vue";
export default {
components: {
AgGridVue,
},
setup() {
const gridApi = ref(null);
const onGridReady = (params) => {
gridApi.value = params.api;
};
const rowData = reactive([]);
const columnDefs = reactive({
value: [
{ field: "brandId", sortable: true, checkboxSelection: true },
{ field: "category" },
{ field: "channel", headerName: "Brand" },
{ field: "channelReferenceId", headerName: "Requested" },
{ field: "id", headerName: "Updated" },
{ field: "status", headerName: "Subject" },
{ field: "subject", headerName: "Requester" },
],
});
const defaultColDef = {
sortable: true,
filter: true,
flex: 1,
};
const { fetchTickets } = useActions({
fetchTickets: "tickets/fetchTickets",
});
const { tickets } = useGetters({
tickets: "tickets/getRowData",
});
function getTickets() {
fetchTickets();
}
getTickets();
onMounted(() => {
rowData.value = tickets.value;
});
return {
onGridReady,
columnDefs,
rowData,
defaultColDef,
tickets,
getTickets,
};
},
As you can see I'm using the vuex-composition-helpers in order to fetch Tickets from an API and then use a getter that will be the main source of data to populate the ag-grid.
I finally came up with a solution for this, for some reason (that to be honest I still don't understand) you have to pass the ag-grid prop value to the component as "rowData.value" (I thought you don't need to specify it that way on the template). So this is the way to implement the component in the template:
<ag-grid-vue
:icons="icons"
class="ag-theme-alpine"
id="myGrid"
:columnDefs="columnDefs.value"
domLayout="autoHeight"
unSortIcon="true"
#grid-ready="onGridReady"
:animateRows="true"
:rowData="rowData.value"
>
And then this is the setup function using composition API:
<script>
import { AgGridVue } from "ag-grid-vue3";
import { useActions, useGetters } from "vuex-composition-helpers";
import { reactive, onMounted, onBeforeMount, ref } from "vue";
export default {
components: {
AgGridVue,
},
setup() {
const gridApi = ref(null);
const onGridReady = (params) => {
gridApi.value = params.api;
gridApi.value.sizeColumnsToFit();
};
const rowData = reactive([]);
const columnDefs = reactive({
value: [
{ field: "brandId", sortable: true, checkboxSelection: true },
{ field: "channel", sortable: true, suppressSizeToFit: true },
{ field: "channelReferenceId", sortable: true },
{ field: "createdOn", sortable: true, suppressSizeToFit: true },
{ field: "status", sortable: true, suppressSizeToFit: true },
{ field: "subject", sortable: true },
],
});
const defaultColDef = {
sortable: true,
filter: true,
flex: 1,
};
const { fetchTickets } = useActions({
fetchTickets: "tickets/fetchTickets",
});
const { tickets } = useGetters({
tickets: "tickets/getRowData",
});
function getTickets() {
fetchTickets();
}
getTickets();
const icons = ref(null);
const columnApi = ref(null);
onBeforeMount(() => {
icons.value = {
sortAscending: '<i class="fas fa-sort-alpha-down text-blue-400"></i>',
sortDescending: '<i class="fas fa-sort-alpha-up text-blue-400"></i>',
sortUnSort: '<i class="fas fa-sort text-blue-400"></i>',
};
});
onMounted(() => {
rowData.value = tickets;
});
return {
onGridReady,
columnDefs,
tickets,
getTickets,
rowData,
defaultColDef,
icons,
columnApi,
};
},
};
</script>
Important things to note:
declare rowData as an array (not an object like the ag-grid website does):
const rowData = reactive([]);
After setting up all the getters, etc and fetching the information:
onMounted(() => {
rowData.value = tickets;
});
I'm trying to create jest tests in order to test the functionality of my ag-grid table.
I currently have tests for expecting the default data in the grid, and testing the functionality of a button which adds an extra row of data to the grid.
I'm trying to edit one of my cells using in-line editing by simulating a double click on the cell I want to be edited. Then followed by a userEvent.type. However the cell never seems to update. I'm not sure if this is because the data hasn't been updated yet due to the asynchronous behaviour or if the simulated typing/click isn't working.
This is my test which is failing:
test("tests the inline cell editing", async () => {
const onClick = jest.fn();
render(<DummyGrid onClick={onClick} />);
const row = screen
.getAllByRole("row")
.filter((item) => item.getAttribute("row-id") === "1");
fireEvent.doubleClick(row[1]);
userEvent.type(row[1], "GT{enter}");
await waitFor(() => {
expect(screen.getByText("GT")).toBeInTheDocument();
});
});
And the following is the DummyGrid ag-grid component:
import React, { useState } from "react";
import { AgGridReact } from "ag-grid-react/lib/agGridReact";
import { ColDef, ValueSetterParams } from "ag-grid-community";
import GridButton from "./GridButton";
import Car from "./car";
import { Button } from "react-bootstrap";
import "ag-grid-community/dist/styles/ag-grid.css";
import "ag-grid-community/dist/styles/ag-theme-alpine-dark.css";
const initialState: Array<Car> = [
{ id: "0", make: "Toyota", modelName: "Celica", price: 35000 },
{ id: "1", make: "Ford", modelName: "Mondeo", price: 32000 },
{ id: "2", make: "Porsche", modelName: "Boxter", price: 70000 },
];
const fieldName = (name: keyof Car) => name;
function getRowNodeId(data: Car) {
return data.id;
}
function onGridReady(params: object) {
// console.log(params);
}
function onRowDataChanged(data: object) {
// console.log(data);
}
const columnDefs: ColDef[] = [
{
headerName: "Make",
field: fieldName("make"),
editable: true,
},
{
headerName: "Model",
field: fieldName("modelName"),
editable: true,
// valueSetter: (params: ValueSetterParams) => {
// onRowDataChanged(params);
// },
},
{
headerName: "Price",
field: fieldName("price"),
editable: true,
},
{
field: "Button",
cellRenderer: "gridButton",
cellRendererParams: {
onClicked: function (
id: string,
make: string,
modelName: string,
price: number
) {
// console.log(id, make, modelName, price);
},
},
},
];
const gridOptions = {
immutableData: true,
suppressScrollOnNewData: true,
columnDefs: columnDefs,
frameworkComponents: {
gridButton: GridButton,
},
};
interface Props {
onClick: () => void;
}
const DummyGrid: React.FC<Props> = ({ onClick }) => {
const [rowData, setRowData] = useState(initialState);
function addData() {
console.log("test");
const newRow: Car = {
id: "3",
make: "Land Rover",
modelName: "Defender",
price: 40000,
};
// console.log(rowData);
setRowData((oldData) => [...oldData, newRow]);
onClick();
}
return (
<div>
<Button data-testid="myButton" onClick={addData}>
Add New Value
</Button>
<div
className="ag-theme-alpine-dark"
style={{ height: "300px", width: "802px" }}
>
<AgGridReact
columnDefs={columnDefs}
defaultColDef={{
sortable: true,
}}
rowData={rowData}
gridOptions={gridOptions}
onGridReady={onGridReady}
onRowDataChanged={onRowDataChanged}
getRowNodeId={getRowNodeId}
suppressColumnVirtualisation={true}
></AgGridReact>
</div>
</div>
);
};
export default DummyGrid;
Any help or advice would be much appreciated. I have researched and found a very small amount of help on testing ag-grid with jest, and nothing on testing in-line ag-grid editing with jest, only the testing of separate buttons which update the grid content.
first please my javascript skill level is not good, but here... I have a table i got from ant.design, im trying to build a frontend with react, so I want to display some data on the table from my database but im finding it had because of the want ant design table is set up.
This is the code
class OrderSummary extends React.Component {
state = {
data: null,
error: null,
loading: false
};
componentDidMount() {
this.handleFetchOrder();
}
handleFetchOrder = () => {
this.setState({ loading: true });
authAxios
.get(orderSummaryURL)
.then(res => {
this.setState({ data: res.data, loading: false });
})
.catch(err => {
// if (err.response.status === 404) {
// this.setState({
// error: "You currently do not have an order",
// loading: false
// });
// } else {
this.setState({ error: err, loading: false });
// }
});
};
render() {
const columns = [
{
title: 'Number',
dataIndex: 'number',
key: 'number',
render: text => <a>{text}</a>,
},
{
title: 'Event Name',
dataIndex: 'name',
key: 'name',
},
{
title: 'Event Price',
dataIndex: 'price',
key: 'price',
},
{
title: 'Quantity',
dataIndex: 'quantity',
key: 'quantity',
},
{
title: 'Total',
dataIndex: 'total',
key: 'total',
},
];
const datasource =
{data.order_items.map((orderItem, i) => {
return (
[
{
key: {orderItem.id},
number: {orderItem.item.title} -{" "},
name: 32,
price: 'NGN' {orderItem.item.price} ,
quantity: {orderItem.quantity},
total: {data.total},
},
// {
// key: 1,
// name: 'John Brown',
// age: 32,
// address: 'New York No. 1 Lake Park',
// tags: ['nice', 'developer'],
// },
];
return (
<Layout>
<div>
<PageHeader
className="site-page-header"
onBack={() => null}
title="Order Summary"
/>
<Table columns={columns}
dataSource={datasource} />
</div>
</Layout>
)
}
};
export default OrderSummary;
Note where i commented out, that part works perfectly because thats how it comes from ant.design
This is the error I keep getting
Failed to compile
./src/containers/OrderSummary.js
Line 95:14: Parsing error: Unexpected token, expected ","
93 |
94 | const datasource =
> 95 | {data.order_items.map((orderItem, i) => {
| ^
96 | return (
97 | [
98 | {
Please help.
First
It seems you didn't close correctly your datasource.
After your ] you need ) } ) } ;
Second
You have to add order_items in data in the state, as it's null and handleFetchOrder is asynchronous. At the time you want to render it will create an error because you try to iterate over a no existing property.
Here a example of what you can try:
In your state declaration:
state = {
data: {
order_items: []
},
error: null,
loading: false
};
In your render function:
Add a const to get your state value:
const data = this.state.data;
const datasource = { data.order_items.map((orderItem, i) => { ... })};
I am trying to optional have row-select features and this should be determined based on a prop that is being passed from parent. I have two grids on a single page, where in one has prop that should enable row selection and the other one does not. But I am getting this error "Cannot read property 'className' of undefined " .
Sandbox: https://codesandbox.io/s/react-table-row-table-alternate-single-row-working-5fr81
import * as React from "react";
import { render } from "react-dom";
import DataGrid from "./DataGrid";
import ShowMore from "./ShowMore";
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
columns: []
};
}
componentDidMount() {
this.getData();
this.getColumns();
}
getData = () => {
const data = [
{ firstName: "Jack", status: "Submitted", items: [1, 2, 3, 4] },
{ firstName: "Simon", status: "Pending", items: [1, 2] },
{ firstName: "Syls", status: "Pending", items: [1] },
{ firstName: "Pete", status: "Approved", items: [] }
];
this.setState({ data });
};
getColumns = () => {
const columns = [
{
Header: "First Name",
accessor: "firstName"
},
{
Header: "Status",
accessor: "status"
},
{
Header: "Items",
accessor: "items",
Cell: row => <ShowMore value={row.value} />
}
];
this.setState({ columns });
};
onClickRow = rowInfo => {
this.setState({ allData: rowInfo }, () => {
console.log(this.state.allData);
});
};
render() {
return (
<>
<DataGrid
data={this.state.data}
columns={this.state.columns}
rowClicked={this.onClickRow}
/>
<DataGrid data={this.state.data} columns={this.state.columns} />
</>
);
}
}
In your onRowClick function in DataGrid.js, your function will return nothing on first render (or until something is clicked). ReactTable is expecting SOMETHING here. If you supply an empty object, it will successfully render.
I am new in Vue and still learning using it. I've been following example from this page: https://vue.ant.design/components/table/
I'm trying to fetch data using json to be displayed using Antd Tables.
But I include the js and css manually using and .
The data calling is fine as i can see from the console logged. But the table is not displaying any records.
I've been trying to code in here:
https://jsfiddle.net/dedychaidir/yvr5o8Lk/4/
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ant-design-vue#1.3.13/dist/antd.css" />
<script src="https://unpkg.com/vue"></script>
<script src="https://cdn.jsdelivr.net/npm/ant-design-vue#1.3.13/dist/antd.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-resource#1.5.1"></script>
<div id="app">
<template>
<a-table :columns="columns" :rowKey="record => record.login.uuid" :dataSource="data" :pagination="pagination" :loading="loading" #change="handleTableChange">
<template slot="name" slot-scope="name">
{{name.first}} {{name.last}}
</template>
</a-table>
</template>
</div>
And this is the script section:
const columns = [{
title: 'Name',
dataIndex: 'name',
sorter: true,
width: '20%',
scopedSlots: {
customRender: 'name'
},
}, {
title: 'Gender',
dataIndex: 'gender',
filters: [{
text: 'Male',
value: 'male'
},
{
text: 'Female',
value: 'female'
},
],
width: '20%',
}, {
title: 'Email',
dataIndex: 'email',
}];
var app = new Vue({
el: "#app",
mounted: function() {
this.fetch();
},
data: function() {
return {
data: [],
pagination: {},
loading: false,
columns,
}
},
methods: {
handleTableChange(pagination, filters, sorter) {
console.log(pagination);
const pager = {
...this.pagination
};
pager.current = pagination.current;
this.pagination = pager;
this.fetch({
results: pagination.pageSize,
page: pagination.current,
sortField: sorter.field,
sortOrder: sorter.order,
...filters,
});
},
fetch(params = {}) {
this.loading = true;
this.$http.get('https://randomuser.me/api',{params:{results:"10"}}).then(response => {
json = JSON.parse(response.bodyText);
const pagination = {
...this.pagination
};
pagination.total = 200;
this.loading = false;
this.data = json.results;
this.pagination = pagination;
console.log(this.data);
}, response => {
console.log(response.body);
});
},
},
});
Please show me if there are some error or mistakes.
Thank you.
I made codesandbox for you with provided code and everything works.
https://codesandbox.io/embed/vue-template-pluqh
Not sure, but maybe you just need to remove first <template> tag inside div#app because its not neccessary