I need an input box in the control box that search and filter the results, like this:
Input and search
Please help, I don't know how to implement this with react-select
Here is an example of implementation:
import React from "react";
import { render } from "react-dom";
import { makeData, Logo, Tips } from "./Utils";
import matchSorter from "match-sorter";
import Select from "react-select";
import "react-select/dist/react-select.css";
// Import React Table
import ReactTable from "react-table";
import "react-table/react-table.css";
class App extends React.Component {
constructor() {
super();
this.state = {
data: makeData(),
filtered: [],
select2: undefined
};
}
onFilteredChangeCustom = (value, accessor) => {
let filtered = this.state.filtered;
let insertNewFilter = 1;
if (filtered.length) {
filtered.forEach((filter, i) => {
if (filter["id"] === accessor) {
if (value === "" || !value.length) filtered.splice(i, 1);
else filter["value"] = value;
insertNewFilter = 0;
}
});
}
if (insertNewFilter) {
filtered.push({ id: accessor, value: value });
}
this.setState({ filtered: filtered });
};
render() {
const { data } = this.state;
return (
<div>
<pre>{JSON.stringify(this.state.filtered, null, 2)}</pre>
<br />
<br />
Extern Select2 :{" "}
<Select
style={{ width: "50%", marginBottom: "20px" }}
onChange={entry => {
this.setState({ select2: entry });
this.onFilteredChangeCustom(
entry.map(o => {
return o.value;
}),
"firstName"
);
}}
value={this.state.select2}
multi={true}
options={this.state.data.map((o, i) => {
return { id: i, value: o.firstName, label: o.firstName };
})}
/>
<ReactTable
data={data}
filterable
filtered={this.state.filtered}
onFilteredChange={(filtered, column, value) => {
this.onFilteredChangeCustom(value, column.id || column.accessor);
}}
defaultFilterMethod={(filter, row, column) => {
const id = filter.pivotId || filter.id;
if (typeof filter.value === "object") {
return row[id] !== undefined
? filter.value.indexOf(row[id]) > -1
: true;
} else {
return row[id] !== undefined
? String(row[id]).indexOf(filter.value) > -1
: true;
}
}}
columns={[
{
Header: "Name",
columns: [
{
Header: "First Name",
accessor: "firstName"
},
{
Header: "Last Name",
id: "lastName",
accessor: d => d.lastName
}
]
},
{
Header: "Info",
columns: [
{
Header: "Age",
accessor: "age"
},
{
Header: "Over 21",
accessor: "age",
id: "over",
Cell: ({ value }) => (value >= 21 ? "Yes" : "No"),
filterMethod: (filter, row) => {
if (filter.value.indexOf("all") > -1) {
return true;
}
if (filter.value.indexOf("true") > -1) {
return row[filter.id] >= 21;
}
return row[filter.id] < 21;
},
Filter: ({ filter, onChange }) => {
return (
<select
onChange={event => {
let selectedOptions = [].slice
.call(event.target.selectedOptions)
.map(o => {
return o.value;
});
this.onFilteredChangeCustom(selectedOptions, "over");
}}
style={{ width: "100%" }}
value={filter ? filter.value : ["all"]}
multiple={true}
>
<option value="all">Show All</option>
<option value="true">Can Drink</option>
<option value="false">Can't Drink</option>
</select>
);
}
}
]
}
]}
defaultPageSize={10}
className="-striped -highlight"
/>
<br />
<Tips />
<Logo />
</div>
);
}
}
render(<App />, document.getElementById("root"));
Related
I'm using react-table v7.8.0 to create a table with 4 columns. I'd like the the table to be sorted by columns date and views. My problem is that the table is only being sorted by the date column.
I have some pagination and manual sorting that appears to be working as expected. I think I've followed the documentation and I'm unsure where my mistake is.
The data is configured in the following file before being passed to a table component:
ViewsPageDayTable.js:
const postDateTemplate = { year: "numeric", month: "short", day: "numeric" }
import Link from "#/components/Link"
import { useMemo } from "react"
import siteMetadata from "#/data/siteMetadata"
import Table from "#/components/homeBrewAnalytics/table"
import LocationCountItem from "#/components/homeBrewAnalytics/locationCountItem"
export default function ViewsPageDayTable({ data }) {
const parsedData = []
for (var i = 0; i < data.length; i++) {
const dataRow = {}
for (var j in data[i]) {
if (j === "date") {
var date = new Date(data[i][j])
dataRow["date"] = date.toLocaleDateString(siteMetadata.locale, postDateTemplate)
} else if (j === "page") {
dataRow["page"] = data[i][j]
} else if (j === "country_count") {
var value = 0
if (data[i][j] == null) {
value = "unknown"
dataRow["country_count"] = null
} else {
value = data[i][j]
value = value.replaceAll("(", "[").replaceAll(")", "]").replaceAll("'", '"')
value = JSON.parse(value)
dataRow["country_count"] = value
}
} else if (j === "views") {
dataRow["views"] = parseInt(data[i][j])
}
}
parsedData.push(dataRow)
}
const PageCellProcessor = ({ value, row: { index }, column: { id } }) => {
return (
<Link href={value} className="hover:underline">
{" "}
{value}{" "}
</Link>
)
}
const LocationCellProcessor = ({ value }) => {
if (value == null) return <div></div>
const result = []
for (var z = 0; z < value.length; z++) {
result.push(<LocationCountItem value={value[z]} />)
}
return (
<div key={value} className="flex flex-shrink">
{result}{" "}
</div>
)
}
const columns = useMemo(
() => [
{
Header: "Date",
accessor: "date",
sortType: (a, b) => {
return new Date(b) - new Date(a)
},
},
{
Header: "Page",
accessor: "page",
Cell: PageCellProcessor,
},
{
Header: "Views",
accessor: "views",
sortType: 'basic',
},
{
Header: "Location",
accessor: "country_count",
Cell: LocationCellProcessor,
},
],
[]
)
return (
<div
id="viewsPerPagePerDay"
className="min-h-32 col-span-3 border-separate border-2 border-slate-800 p-3"
>
<Table columns={columns} data={parsedData} />
</div>
)
}
Table.js:
import { React, useMemo } from "react"
import { useTable, useFilters, useSortBy, usePagination } from "react-table"
import { useState } from "react"
export default function Table({ columns, data, isPaginated = true }) {
const [filterInput, setFilterInput] = useState("")
const handleFilterChange = (e) => {
const value = e.target.value || undefined
setFilter("page", value)
setFilterInput(value)
}
const {
getTableProps,
getTableBodyProps,
headerGroups,
page,
prepareRow,
setFilter,
canPreviousPage,
canNextPage,
pageOptions,
nextPage,
previousPage,
state: { pageIndex, pageSize },
} = useTable(
{
columns,
data,
initialState: {
defaultCanSort: true,
disableSortBy: false,
manualSortBy: true,
sortBy: useMemo(
() => [
{
id: "date",
desc: false,
},
{
id: "views",
desc: true,
},
],
[]
),
pageIndex: 0,
pageSize: 15,
manualPagination: true,
},
},
useFilters,
useSortBy,
usePagination
)
return (
<>
<div className="flex justify-between align-middle">
<div> Page Views</div>
<input
className="mr-0 rounded-sm border border-gray-700 dark:border-gray-500 "
value={filterInput}
onChange={handleFilterChange}
placeholder={" Page name filter"}
/>
</div>
<table {...getTableProps()}>
<thead>
{headerGroups.map((headerGroup) => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map((column) => (
<th
{...column.getHeaderProps(column.getSortByToggleProps())}
className={
column.isSorted ? (column.isSortedDesc ? "sort-desc" : "sort-asc") : ""
}
>
{column.render("Header")}
</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{page.map((row, _) => {
prepareRow(row)
return (
<tr {...row.getRowProps()}>
{row.cells.map((cell) => {
return <td {...cell.getCellProps()}>{cell.render("Cell")}</td>
})}
</tr>
)
})}
</tbody>
</table>
{Boolean(isPaginated) && (
<div id="pagination">
<div id="pageNum">
page {pageIndex + 1} of {pageOptions.length}
</div>{" "}
<div id="nextPrevButtons">
{canPreviousPage ? (
<div id="backButton" onClick={() => previousPage()}>
Previous
</div>
) : null}
{canNextPage ? (
<div id="nextButton" onClick={() => nextPage()}>
Next{" "}
</div>
) : null}
</div>
</div>
)}
</>
)
}
Im using Antd library and i can't seem to find where i have the bug.
This is my EditableTableCell component
import React, {Component} from 'react';
import { Form } from '#ant-design/compatible';
import '#ant-design/compatible/assets/index.css';
import { Input, InputNumber, Select, DatePicker } from "antd";
import moment from "moment";
import {EditableContext} from "./EditableTableRow";
const FormItem = Form.Item;
const Option = Select.Option;
class EditableTableCell extends Component {
getInput = (record, dataIndex, title, getFieldDecorator) => {
switch (this.props.inputType) {
case "number":
return (
<FormItem style={{ margin: 0 }}>
{getFieldDecorator(dataIndex, {
rules: [
{
required: true,
message: `Please Input ${title}!`
}
],
initialValue: record[dataIndex]
})(
<InputNumber formatter={value => value} parser={value => value} />
)}
</FormItem>
);
case "date":
return (
<FormItem style={{ margin: 0 }}>
{getFieldDecorator(dataIndex, {
initialValue: moment(record[dataIndex], this.dateFormat)
})(<DatePicker format={this.dateFormat} />)}
</FormItem>
);
case "select":
return (
<FormItem style={{ margin: 0 }}>
{getFieldDecorator(dataIndex, {
initialValue: record[dataIndex]
})(
<Select style={{ width: 150 }}>
{[...Array(11).keys()]
.filter(x => x > 0)
.map(c => `Product ${c}`)
.map((p, index) => (
<Option value={p} key={index}>
{p}
</Option>
))}
</Select>
)}
</FormItem>
);
default:
return (
<FormItem style={{ margin: 0 }}>
{getFieldDecorator(dataIndex, {
rules: [
{
required: true,
message: `Please Input ${title}!`
}
],
initialValue: record[dataIndex]
})(<Input />)}
</FormItem>
);
}
}
render() {
const { editing, dataIndex, title, inputType, record, index,...restProps} = this.props;
return (
<EditableContext.Consumer>
{form => {
const { getFieldDecorator } = form;
return (
<td {...restProps}>
{editing ?
this.getInput(record, dataIndex, title, getFieldDecorator)
: restProps.children}
</td>
);
}}
</EditableContext.Consumer>
);
}
}
export default EditableTableCell;
This is my EditableTableCell component
import React, {Component} from 'react';
import { Form} from '#ant-design/compatible';
export const EditableContext = React.createContext();
class EditableTableRow extends Component {
render() {
return (
<EditableContext.Provider value={this.props.form}>
<tr {...this.props} />
</EditableContext.Provider>
);
}
}
export default EditableTableRow=Form.create()(EditableTableRow);
This is my ProductsPage component im having bug in
import React, {Component} from 'react';
import {Button, Layout, notification, Popconfirm, Space, Table,Typography} from "antd";
import {Link} from "react-router-dom";
import {Content} from "antd/es/layout/layout";
import EditableTableRow, {EditableContext} from "../components/EditableTableRow";
import EditableTableCell from "../components/EditableTableCell";
import API from "../server-apis/api";
import {employeesDataColumns} from "../tableColumnsData/employeesDataColumns";
import {CheckCircleFilled, InfoCircleFilled} from "#ant-design/icons";
class ProductsPage extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
error: null,
isLoaded: false,
editingKey: "",
errorMessage: "",
}
}
columns = [
...employeesDataColumns,
{
title: "Actions",
dataIndex: "actions",
width: "10%",
render: (text, record) => {
const editable = this.isEditing(record);
return editable ? (
<span>
<EditableContext.Consumer>
{form => (<a onClick={() => this.saveData(form, record.username)} style={{ marginRight: 8 }}>Save</a>)}
</EditableContext.Consumer>
<a onClick={this.cancel}>Cancel</a>
</span>
) : (
<Space size="middle">
<a onClick={() => this.edit(record.username)}>Edit</a>
<Popconfirm title="Are you sure you want to delete this product?"
onConfirm={() => this.remove(record.username)}>
<a style={{color:"red"}}>Delete</a>
</Popconfirm>
</Space>
);
},
}
];
isEditing = (record) => {
return record.username === this.state.editingKey;
};
edit(username) {
this.setState({editingKey:username});
}
cancel = () => {
this.setState({ editingKey: ""});
};
componentDidMount() {
this.setState({ loading: true });
const token="Bearer "+ JSON.parse(localStorage.getItem("token"));
API.get(`users/all`,{ headers: { Authorization: token}})
.then(res => {
// console.log(res.data._embedded.productList);
const employees = res.data._embedded.employeeInfoDtoList;
this.setState({loading: false,data:employees });
})
}
async remove(username) {
const token="Bearer "+ JSON.parse(localStorage.getItem("token"));
API.delete(`/users/${username}`,{ headers: { Authorization: token}})
.then(() => {
let updatedProducts = [...this.state.data].filter(i => i.username !== username);
this.setState({data: updatedProducts});
this.successfullyAdded("Employee is deleted. It wont have any access to the website anymore.")
}).catch(()=>this.errorHappend("Failed to delete"));
}
hasWhiteSpace(s) {
return /\s/g.test(s);
}
saveData(form,username) {
form.validateFields((error, row) => {
if (error) {
return;
}
const newData = [...this.state.data];
const index = newData.findIndex(item => username === item.username);
const item = newData[index];
newData.splice(index, 1, {
...item,
...row
});
const token="Bearer "+ JSON.parse(localStorage.getItem("token"));
const response = API.put(`/users/${username}/update`, row,{ headers: { Authorization: token}})
.then((response) => {
this.setState({ data: newData, editingKey: ""});
this.successfullyAdded("Empolyee info is updated")
})
.catch(error => {
this.setState({ errorMessage: error.message });
this.errorHappend("Failed to save changes.")
console.error('There was an error!', error);
});
});
}
successfullyAdded = (message) => {
notification.info({
message: `Notification`,
description:message,
placement:"bottomRight",
icon: <CheckCircleFilled style={{ color: '#0AC035' }} />
});
};
errorHappend = (error) => {
notification.info({
message: `Notification`,
description:
`There was an error! ${error}`,
placement:"bottomRight",
icon: <InfoCircleFilled style={{ color: '#f53333' }} />
});
};
render() {
const components = {
body: {
row: EditableTableRow,
cell: EditableTableCell
}
};
const columns = this.columns.map(col => {
if (!col.editable) {
return col;
}
return {
...col,
onCell: record => {
const checkInput = index => {
switch (index) {
case "price":
return "number";
default:
return "text";
}
};
return {
record,
// inputType: col.dataIndex === "age" ? "number" : "text",
inputType: checkInput(col.dataIndex),
dataIndex: col.dataIndex,
title: col.title,
editing: this.isEditing(record)
};
}
};
});
const { data, loading } = this.state;
return (
<Layout>
<div>
<Link to="/add-product">
<Button style={{float:"right", background: "#0AC035",marginBottom:"1em", marginTop:"1em" }}
type="primary">New emplyee</Button>
</Link>
</div>
<Content>
<Table components={components} bordered dataSource={data} columns={columns} loading={loading} rowKey={data.username} rowClassName="editable-row"/>
</Content>
</Layout>
);
}
}
export default ProductsPage;
This is the bug I'm having:
enter image description here
And i want to have this result like its shown in Antd docs:
enter image description here
Id really appreciate if you take a look and help me figure out where im wrong
Updated Solution:
I find the issue. In render where you map the columns, you just return the column if it's not an editable column. You can check the code below. I added a check if it's dataIndex === 'actions', then return the following code:
Please Follow the link:
https://react-ts-v3fbst.stackblitz.io
Changes:
1.In columns, i remove the render function from the action object:
{
title: 'Actions',
dataIndex: 'actions',
width: '10%',
},
2. In render function where you map the columns, add the following code before this condition if(!col.editable) {,:
if (col.dataIndex === 'actions') {
return {
...col,
render: (text, record) => {
const editable = this.isEditing(record);
return editable ? (
<span>
<EditableContext.Consumer>
{(form) => (
<a onClick={() => this.saveData(form, record.username)} style={{ marginRight: 8 }}>
Save
</a>
)}
</EditableContext.Consumer>
<a onClick={this.cancel}>Cancel</a>
</span>
) : (
<Space size='middle'>
<a onClick={() => this.edit(record.username)}>Edit</a>
<Popconfirm title='Are you sure you want to delete this product?' onConfirm={() => this.remove(record.username)}>
<a style={{ color: 'red' }}>Delete</a>
</Popconfirm>
</Space>
);
}
};
}
When you click on edit, you set the username as key for that particular row for editing, make sure you have username in each record. I tested this using the following data:
const data = [
{ id: 8, name: 'baun', model: '2022', color: 'black', price: 358, quantity: 3, username: 'brvim' },
{ id: 3, name: 'galileo', model: '20221', color: 'white', price: 427, quantity: 7, username: 'john' }
];
Most important, you should select that attribute as key that is unique in all records. As you are using username, i don't know what is your business logic or data looks like, but technically each record can have same username. So you must select something that would always be unique in your complete data.
I want the default value of my dropdown to be defaultValue={item.taste} (value from match.json) but it's not working... (go to /menu/Menu1 and Pea Soup)
import Select from "react-select";
export default function CustomDropdown({ style, options, defaultValue }) {
return (
<div style={style}>
<Select options={options} defaultValue={defaultValue} />
</div>
);
}
MenuItemDisplay:
export default function MenuItemDisplay() {
const { menuId, itemId } = useParams();
const { match } = JsonData;
const matchData = match.find((el) => el._id_menu === menuId)?._ids ?? [];
const item = matchData.find((el) => el._id === itemId);
const styles = {
select: {
width: "100%",
maxWidth: 150
}
};
const TASTE = [
{ label: "Good", value: "Good" },
{ label: "Medium", value: "Medium" },
{ label: "Bad", value: "Bad" }
];
...
return (
<>
<div className="TextStyle">
{"Taste "}
<CustomDropdown
style={styles.select}
options={TASTE}
defaultValue={item.taste}
//The default value is not working only if it's
//TASTE[0]
/>
</div>
...
</>
);
}
Here the link for the code
As defaultValue you need to pass one of the objects of the TASTE array. You can do this:
<CustomDropdown
style={styles.select}
options={TASTE}
defaultValue={TASTE.find(t => t.label === item.taste)}
/>
I used Ant table to show some information.
https://codesandbox.io/s/proud-architecture-lsb85?file=/src/index.js
I want to customize the position of the checkbox for row selection.
In this application, you can see the header in the following order of checkbox, Name, Age, Address but I want to swap checkbox and Name.
You can add checkbox columns and customize render and titleRender of it to checkbox and then handle the events. if you incounter performance issue you have to add some memoization on columns or evenet handlers.
import React from "react";
import ReactDOM from "react-dom";
import "antd/dist/antd.css";
import { Table, Button, Checkbox } from "antd";
const data = [];
for (let i = 0; i < 46; i++) {
data.push({
key: i,
name: `Edward King ${i}`,
age: 32,
address: `London, Park Lane no. ${i}`
});
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
selectedRowKeys: [], // Check here to configure the default column
loading: false,
allChecked: false
};
this.columns = [
{
title: "Name",
dataIndex: "name"
},
{
dataIndex: "checked",
title: () => {
return (
<Checkbox
checked={this.state.allChecked}
onChange={(e) => this.selectAll(e)}
></Checkbox>
);
},
render: (text, rec, index) => {
return (
<Checkbox
checked={
this.state.selectedRowKeys.includes(rec.key) ||
this.state.allChecked
}
onChange={(e) => this.onChange(e, rec)}
></Checkbox>
);
}
},
{
title: "Age",
dataIndex: "age"
},
{
title: "Address",
dataIndex: "address"
}
];
}
start = () => {
this.setState({ loading: true });
// ajax request after empty completing
setTimeout(() => {
this.setState({
selectedRowKeys: [],
loading: false
});
}, 1000);
};
onChange = (e, rec) => {
const checked = e.target.checked;
if (checked) {
this.setState((state) => ({
...state,
selectedRowKeys: [...state.selectedRowKeys, rec.key]
}));
} else {
this.setState((state) => ({
...state,
selectedRowKeys: [
...state.selectedRowKeys.filter((item) => item !== rec.key)
]
}));
}
};
selectAll = (e) => {
const checked = e.target.checked;
if (checked) {
this.setState((state) => ({
...state,
allChecked: true
}));
} else {
this.setState((state) => ({
...state,
allChecked: false
}));
}
};
onSelectChange = (selectedRowKeys) => {
console.log("selectedRowKeys changed: ", selectedRowKeys);
this.setState({ selectedRowKeys });
};
render() {
const { loading, selectedRowKeys } = this.state;
const hasSelected = selectedRowKeys.length > 0;
return (
<div>
<div style={{ marginBottom: 16 }}>
<Button
type="primary"
onClick={this.start}
disabled={!hasSelected}
loading={loading}
>
Reload
</Button>
<span style={{ marginLeft: 8 }}>
{hasSelected ? `Selected ${selectedRowKeys.length} items` : ""}
</span>
</div>
<Table columns={this.columns} dataSource={data} />
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("container"));
I mimic code at https://github.com/primefaces/primereact/blob/master/src/components/utils/ClassNames.js
and
https://github.com/primefaces/primereact/blob/master/src/showcase/datatable/DataTablePaginatorDemo.js
My code
export function classNames(...args) {
if (args) {
let classes = [];
for (let i = 0; i < args.length; i++) {
let className = args[i];
if (!className) continue;
const type = typeof className;
if (type === 'string' || type === 'number') {
classes.push(className);
} else if (type === 'object') {
const _classes = Array.isArray(className)
? className
: Object.entries(className).map(([key, value]) =>
!!value ? key : null
);
classes = _classes.length
? classes.concat(_classes.filter((c) => !!c))
: classes;
}
}
return classes.join(' ');
}
return undefined;
}
import React, { useState, useEffect, useRef, Component } from 'react';
import { DataTable } from 'primereact/datatable';
import { Column } from 'primereact/column';
import { Button } from 'primereact/button';
import { Toast } from 'primereact/toast';
import { InputText } from 'primereact/inputtext';
import Moment from 'react-moment';
import { AcctgTransService } from '../service/AcctgTransService';
import { getTokenCookie } from '../TokenCookie';
import { Dialog } from 'primereact/dialog';
import { Dropdown } from 'primereact/dropdown';
import { Calendar } from 'primereact/calendar';
import { useTranslation } from 'react-i18next';
import { Const, ServiceHandle } from '../utilities';
import i18n from 'i18next';
import axios from 'axios';
import { Ripple } from 'primereact/core';
import { CustomerService } from '../service/CustomerService';
import { classNames } from 'utils/ClassNames.js';
export class AcctgTrans2 extends Component {
constructor(props) {
super(props);
this.state = {
customers1: [],
customers2: [],
customers3: [],
first1: 0,
rows1: 10,
first2: 0,
rows2: 10,
currentPage: 1,
pageInputTooltip: "Press 'Enter' key to go to this page.",
};
this.customerService = new CustomerService();
this.onCustomPage1 = this.onCustomPage1.bind(this);
this.onCustomPage2 = this.onCustomPage2.bind(this);
this.onPageInputKeyDown = this.onPageInputKeyDown.bind(this);
this.onPageInputChange = this.onPageInputChange.bind(this);
}
onCustomPage1(event) {
this.setState({
first1: event.first,
rows1: event.rows,
currentPage: event.page + 1,
});
}
onCustomPage2(event) {
this.setState({
first2: event.first,
rows2: event.rows,
});
}
onPageInputKeyDown(event, options) {
if (event.key === 'Enter') {
const page = parseInt(this.state.currentPage);
if (page < 0 || page > options.totalPages) {
this.setState({
pageInputTooltip: `Value must be between 1 and ${options.totalPages}.`,
});
} else {
const first = this.state.currentPage ? options.rows * (page - 1) : 0;
this.setState({
first1: first,
pageInputTooltip: "Press 'Enter' key to go to this page.",
});
}
}
}
onPageInputChange(event) {
this.setState({ currentPage: event.target.value });
}
componentDidMount() {
this.customerService
.getCustomersLarge()
.then((data) => this.setState({ customers1: data }));
this.customerService
.getCustomersLarge()
.then((data) => this.setState({ customers2: data }));
this.customerService
.getCustomersLarge()
.then((data) => this.setState({ customers3: data }));
}
render() {
const paginatorLeft = (
<Button type="button" icon="pi pi-refresh" className="p-button-text" />
);
const paginatorRight = (
<Button type="button" icon="pi pi-cloud" className="p-button-text" />
);
const template1 = {
layout:
'PrevPageLink PageLinks NextPageLink RowsPerPageDropdown CurrentPageReport',
PrevPageLink: (options) => {
return (
<button
type="button"
className={options.className}
onClick={options.onClick}
disabled={options.disabled}>
<span className="p-p-3">Previous</span>
<Ripple />
</button>
);
},
NextPageLink: (options) => {
return (
<button
type="button"
className={options.className}
onClick={options.onClick}
disabled={options.disabled}>
<span className="p-p-3">Next</span>
<Ripple />
</button>
);
},
PageLinks: (options) => {
if (
(options.view.startPage === options.page &&
options.view.startPage !== 0) ||
(options.view.endPage === options.page &&
options.page + 1 !== options.totalPages)
) {
const className = classNames(options.className, {
'p-disabled': true,
});
return (
<span className={className} style={{ userSelect: 'none' }}>
...
</span>
);
}
return (
<button
type="button"
className={options.className}
onClick={options.onClick}>
{options.page + 1}
<Ripple />
</button>
);
},
RowsPerPageDropdown: (options) => {
const dropdownOptions = [
{ label: 10, value: 10 },
{ label: 20, value: 20 },
{ label: 50, value: 50 },
{ label: 'All', value: options.totalRecords },
];
return (
<Dropdown
value={options.value}
options={dropdownOptions}
onChange={options.onChange}
appendTo={document.body}
/>
);
},
CurrentPageReport: (options) => {
return (
<span
className="p-mx-3"
style={{ color: 'var(--text-color)', userSelect: 'none' }}>
Go to{' '}
<InputText
size="2"
className="p-ml-1"
value={this.state.currentPage}
tooltip={this.state.pageInputTooltip}
onKeyDown={(e) => this.onPageInputKeyDown(e, options)}
onChange={this.onPageInputChange}
/>
</span>
);
},
};
const template2 = {
layout: 'RowsPerPageDropdown CurrentPageReport PrevPageLink NextPageLink',
RowsPerPageDropdown: (options) => {
const dropdownOptions = [
{ label: 10, value: 10 },
{ label: 20, value: 20 },
{ label: 50, value: 50 },
];
return (
<>
<span
className="p-mx-1"
style={{ color: 'var(--text-color)', userSelect: 'none' }}>
Items per page:{' '}
</span>
<Dropdown
value={options.value}
options={dropdownOptions}
onChange={options.onChange}
appendTo={document.body}
/>
</>
);
},
CurrentPageReport: (options) => {
return (
<span
style={{
color: 'var(--text-color)',
userSelect: 'none',
width: '120px',
textAlign: 'center',
}}>
{options.first} - {options.last} of {options.totalRecords}
</span>
);
},
};
return (
<div>
<div className="content-section implementation">
<div className="card">
<h5>Basic</h5>
<DataTable
value={this.state.customers1}
paginator
paginatorTemplate="CurrentPageReport FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink RowsPerPageDropdown"
currentPageReportTemplate="Showing {first} to {last} of {totalRecords}"
rows={10}
rowsPerPageOptions={[10, 20, 50]}
paginatorLeft={paginatorLeft}
paginatorRight={paginatorRight}>
<Column field="name" header="Name"></Column>
<Column field="country.name" header="Country"></Column>
<Column field="company" header="Company"></Column>
<Column
field="representative.name"
header="Representative"></Column>
</DataTable>
<h5>Custom Paginator Template</h5>
<DataTable
value={this.state.customers2}
paginator
paginatorTemplate={template1}
first={this.state.first1}
rows={this.state.rows1}
onPage={this.onCustomPage1}>
<Column field="name" header="Name"></Column>
<Column field="country.name" header="Country"></Column>
<Column field="company" header="Company"></Column>
<Column
field="representative.name"
header="Representative"></Column>
</DataTable>
<DataTable
value={this.state.customers3}
paginator
paginatorTemplate={template2}
first={this.state.first2}
rows={this.state.rows2}
onPage={this.onCustomPage2}
paginatorClassName="p-jc-end"
className="p-mt-6">
<Column field="name" header="Name"></Column>
<Column field="country.name" header="Country"></Column>
<Column field="company" header="Company"></Column>
<Column
field="representative.name"
header="Representative"></Column>
</DataTable>
</div>
</div>
</div>
);
}
}
Error
E:\monte\gsreact>npm run build
> gsreact#0.1.0 build
> react-scripts build && rmdir /s E:\xx\xx\runtime\base-component\webroot\screen\webroot\xx && move build E:\xx\xx\runtime\base-component\webroot\screen\webroot\xx
Creating an optimized production build...
Failed to compile.
.\src\components\AcctgTrans2.js
Cannot find module: 'utils/ClassNames.js'. Make sure this package is installed.
You can install this package by running: npm install utils/ClassNames.js.
E:\xx\xx>
How to fix this error?
Quick Solution
You can change:
import { classNames } from 'utils/ClassNames.js';
To:
import { classNames } from './utils/ClassNames.js';
Without the relative route, the import thinks it's a library.
Configuration
If you want to configure and you've used create-react-app: https://create-react-app.dev/docs/importing-a-component/#absolute-imports
In any other case:
https://github.com/tleunen/babel-plugin-module-resolver
https://github.com/entwicklerstube/babel-plugin-root-import