I am using an npm package called react-datatable for a project and I am trying to build out a way to search through the data. I found a repo where someone was able to do this; however, his react skills are above mine and I cannot seem to make his code work properly on my end. I would just like to know why it isn't rendering anything on my front end. Any advice would be helpful. Thank you.
His code:
import React from 'react';
import styled from 'styled-components';
import { storiesOf } from '#storybook/react';
import faker from 'faker';
import Button from '../shared/Button';
import DataTable from '../../../src/index';
const createUser = () => ({
id: faker.random.uuid(),
name: faker.name.findName(),
email: faker.internet.email(),
address: faker.address.streetAddress(),
bio: faker.lorem.sentence(),
image: faker.image.avatar(),
});
const createUsers = (numUsers = 5) =>
new Array(numUsers).fill(undefined).map(createUser);
const fakeUsers = createUsers(2000);
const TextField = styled.input`
height: 32px;
width: 200px;
border-radius: 3px;
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
border: 1px solid #e5e5e5;
padding: 0 32px 0 16px;
&:hover {
cursor: pointer;
}
`;
const ClearButton = styled(Button)`
border-top-left-radius: 0;
border-bottom-left-radius: 0;
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
height: 34px;
width: 32px;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
`;
const FilterComponent = ({ filterText, onFilter, onClear }) => (
<>
<TextField id="search" type="text" placeholder="Filter By Name" aria-label="Search Input" value={filterText} onChange={onFilter} />
<ClearButton type="button" onClick={onClear}>X</ClearButton>
</>
);
const columns = [
{
name: 'Name',
selector: 'name',
sortable: true,
},
{
name: 'Email',
selector: 'email',
sortable: true,
},
{
name: 'Address',
selector: 'address',
sortable: true,
},
];
const BasicTable = () => {
const [filterText, setFilterText] = React.useState('');
const [resetPaginationToggle, setResetPaginationToggle] = React.useState(false);
const filteredItems = fakeUsers.filter(item => item.name && item.name.toLowerCase().includes(filterText.toLowerCase()));
const subHeaderComponentMemo = React.useMemo(() => {
const handleClear = () => {
if (filterText) {
setResetPaginationToggle(!resetPaginationToggle);
setFilterText('');
}
};
return <FilterComponent onFilter={e => setFilterText(e.target.value)} onClear={handleClear} filterText={filterText} />;
}, [filterText, resetPaginationToggle]);
return (
<DataTable
title="Contact List"
columns={columns}
data={filteredItems}
pagination
paginationResetDefaultPage={resetPaginationToggle} // optionally, a hook to reset pagination to page 1
subHeader
subHeaderComponent={subHeaderComponentMemo}
selectableRows
persistTableHead
/>
);
};
storiesOf('Filtering', module)
.add('Example 1', () => <BasicTable />)
My code:
import React from 'react';
import NotesListHtml from './NoteListHtml'
import DataTable from 'react-data-table-component';
const FilterComponent = ( { filterText, onClear, onFilter }) => (
<>
<input id="search" type="text" placeholder="Filter By Name" aria-label="Search Input" value={filterText} onChange={onFilter} />
<button type="button" onClick={onClear}>X</button>
</>
)
const BasicTable = (props) => {
let result = props.notes.map(function(el) {
var o = Object.assign({}, el);
o.fullName = `${props.data.first_name} ${props.data.last_name}`;
return o;
})
const ExpandableComponent = ({ data }) =>{
return(<p style={{padding:'20px'}}>{data.contentBody}</p>)
}
const columns = [
{
name: 'Organization',
selector: row => row.type[0].label || row.type,
sortable: true,
wrap:true
},
{
name: 'Title',
selector: 'title',
sortable: true,
},
{
name: 'Date',
selector: row=>row.createdAt.split('T')[0],
sortable: true,
},
{
name: 'Author',
selector: 'fullName',
sortable: true,
},
];
const customStyles = {
headCells: {
style: {
backgroundColor:'#f3f7f9',
},
},
cells: {
style: {
color:'#79838b'
},
},
};
const [filterText, setFilterText] = React.useState('');
const [resetPaginationToggle, setResetPaginationToggle] = React.useState(false);
const filteredItems = props.notes.filter(item => item.type[0].label && item.type[0].label.toLowerCase().includes(filterText.toLowerCase()))
const subHeaderComponentMemo = React.useMemo(() => {
console.log('subheader')
const handleClear = () => {
console.log('hit1')
if (filterText) {
setResetPaginationToggle(!resetPaginationToggle);
setFilterText('');
}
}
console.log('beforereturn');
return (
<>
{/* <input id="search" type="text" placeholder="Filter By Name" aria-label="Search Input" value={filterText} onChange={onFilter} /> */}
<button type="button" onClick={handleClear}>X</button>
</>
)
}, [filterText, resetPaginationToggle])
return (
<>
<DataTable
subHeaderComponent={subHeaderComponentMemo}
className='table'
columns={columns}
data={filteredItems}
pagination={true}
highlightOnHover={true}
pointerOnHover={true}
expandableRows={true}
expandOnRowClicked={true}
expandableRowsComponent={<ExpandableComponent data={result} />}
paginationResetDefaultPage={resetPaginationToggle} // optionally, a hook to reset pagination to page 1
customStyles={customStyles}
subHeader={false}
/>
</>
);
}
export default BasicTable;
Related
I've been trying to upload multiple images WITH preview in NextJS (React). I tried changing the constants to arrays and tried mapping through them but it just doesn't seem to work and I don't know how I could get it to work.
I've made a component out of the upload functionality and here is the code that works for uploading a single image with a Preview.
uploadImage.js
import React, { useEffect, useRef, useState } from "react";
import styled from "styled-components";
function imageUpload() {
const [image, setImage] = useState(null);
const fileInputRef = useRef();
const [preview, setPreview] = useState();
useEffect(() => {
if (image) {
const reader = new FileReader();
reader.onloadend = () => {
setPreview(reader.result);
};
reader.readAsDataURL(image);
} else {
}
}, [image]);
return (
<div className="flex ">
<StyledImg
src={preview}
style={{ objectFit: "cover" }}
onClick={() => setImage(null)}
/>
<StyledButton
onClick={(e) => {
e.preventDefault();
fileInputRef.current.click();
}}
/>
<input
type="file"
style={{ display: "none" }}
accept="image/*"
ref={fileInputRef}
onChange={(e) => {
const file = e.target.files[0];
if (file && file.type.substr(0, 5) === "image") {
setImage(file);
} else {
setImage(null);
}
}}
/>
</div>
);
}
const StyledButton = styled.button`
`;
const StyledImg = styled.img`
width: 100px;
height: 100px;
margin-right: 10px;
`;
export default imageUpload;
Based on these references https://react-dropzone.js.org/#section-previews and https://stackblitz.com/edit/nextjs-buk2rw?file=pages%2Findex.js I replaced my code with the following
ImageUpload.js
import React, { useEffect, useState } from "react";
import { useDropzone } from "react-dropzone";
import styled from "styled-components";
function DragAndDrop() {
const [files, setFiles] = useState([]);
const { getRootProps, getInputProps } = useDropzone({
accept: "image/*",
onDrop: (acceptedFiles) => {
setFiles((files) => [
...files,
...acceptedFiles.map((file) =>
Object.assign(file, {
key: file.name + randomId(), // to allow adding files with same name
preview: URL.createObjectURL(file),
})
),
]);
},
});
const removeFile = (file) => {
setFiles((files) => {
const newFiles = [...files];
newFiles.splice(file, 1);
return newFiles;
});
};
const thumbs = files.map((file, i) => (
<div style={thumb} key={file.key}>
<div style={thumbInner}>
<img src={file.preview} style={img} />
</div>
<button type="button" style={removeButton} onClick={() => removeFile(i)}>
X
</button>
</div>
));
useEffect(
() => () => {
files.forEach((file) => URL.revokeObjectURL(file.preview));
},
[files]
);
return (
<section className="container">
<div {...getRootProps({ className: "dropzone" })}>
<input {...getInputProps()} />
<StyledP className="flex align-center justify-center">
Glisser Images Ici ou Cliquer pour selectionner
</StyledP>
</div>
<aside style={thumbsContainer}>{thumbs}</aside>
</section>
);
}
const StyledP = styled.p`
cursor: pointer;
padding: 30px;
`;
const randomId = () => (Math.random() + 1).toString(36).substring(7);
const thumbsContainer = {
display: "flex",
flexDirection: "row",
flexWrap: "wrap",
marginTop: 16,
};
const thumb = {
display: "inline-flex",
borderRadius: 2,
border: "1px solid #eaeaea",
marginBottom: 8,
marginRight: 8,
width: 100,
height: 100,
padding: 4,
boxSizing: "border-box",
position: "relative",
};
const thumbInner = {
display: "flex",
minWidth: 0,
overflow: "hidden",
};
const img = {
display: "block",
width: "auto",
height: "100%",
};
const removeButton = {
color: "red",
position: "absolute",
right: 4,
};
export default DragAndDrop;
I want only the clicked icon to be changed in color but the whole icons’ color change when clicked.
I know it’s basically because useState is not assigned to each click event but I’m stuck here and don’t know how to approach.
const moods = [
{ icon: faGrinStars, mood: 'super' },
{ icon: faSmile, mood: 'good' },
{ icon: faMeh, mood: 'soso' },
{ icon: faFrown, mood: 'bad' },
{ icon: faAngry, mood: 'angry' },
];
const [clicked, setClicked] = useState(false);
const handleClick = () => {
setClicked(!clicked);
};
return (
<StyledDiv>
{moods.map((mood) => (
<div key={mood.mood}>
<input
type='radio'
name='mood'
id={mood.mood}
onClick={handleClick}
/>
<label htmlFor={mood.mood}>
<FontAwesomeIcon
icon={mood.icon}
size='2x'
style={clicked ? { color: 'red' } : { color: '#5e5c5a' }}
/>
</label>
</div>
))}
</StyledDiv>
);
};
const StyledDiv = styled.div`
${({ theme }) => {
const { colors } = theme;
return css`
input {
display: none;
}
`;
}}
`;
export default MoodIcons;
Use an array to save all state of clicked button status.
Something like this:
const moods = [
{ icon: faGrinStars, mood: 'super' },
{ icon: faSmile, mood: 'good' },
{ icon: faMeh, mood: 'soso' },
{ icon: faFrown, mood: 'bad' },
{ icon: faAngry, mood: 'angry' },
];
const [clicked, setClicked] = useState([false, false, false, false, false]);
const handleClick = (i) => {
setClicked(prevState => {
const nextStaet = [...prevState];
nextStaet[i] = !nextStaet[i];
return nextStaet;
});
};
return (
<StyledDiv>
{moods.map((mood, index) => (
<div key={mood.mood}>
<input
type='radio'
name='mood'
id={mood.mood}
onClick={() => handleClick(index)}
/>
<label htmlFor={mood.mood}>
<FontAwesomeIcon
icon={mood.icon}
size='2x'
style={clicked[clicked] ? { color: 'red' } : { color: '#5e5c5a' }}
/>
</label>
</div>
))}
</StyledDiv>
);
};
const StyledDiv = styled.div`
${({ theme }) => {
const { colors } = theme;
return css`
input {
display: none;
}
`;
}}
`;
export default MoodIcons;
I have a code like this
const Products = () => {
const [products, setProducts] = useState([{
id: 1,
name: '1 - 10'
}, {
id: 2,
name: '11 - 100'
},
{
id: 3,
name: '101 - 1000'
},
{
id: 4,
name: '>1000'
}
]);
const [productsPicked, setProductsPicked] = useState([
{
id: 1,
name: '1 - 10'
}, {
id: 2,
name: '11 - 100'
}
]);
const { control, register, handleSubmit, getValues, formState: { errors } } = useForm({
mode: 'onSubmit'
});
const complete = (data) => {
console.log(data);
}
return (
<form onSubmit={handleSubmit(complete)}>
{products.map((product, i) => (
<Controller key={i} control={control} name="title" render={({ field }) => (
// i need to checkbox that picked checked by default, and i can update productsPicked here
)} />
))}
</form>
)
}
All i need to do is create a list of checkbox products list. if product in list productsPicked, they default checked and i can update can update productsPicked b,using react-hook-form v7. I am super new to react and doesn't know how to complete. Sorry for my bad english. thank you so much.
try this into the map.
<div className="checkbox">
<label className="select_label">
<input
className="checkbox"
type="checkbox"
/>
{product.name}
</label>
</div>
And this is the css code:
.select_ul {
display: flex;
justify-content: space-between;
}
.checkbox .select_label{
margin: 1px;
}
.checkbox {
display: flex;
}
.select_a{
font-size: 19px;
color: black;
}
I am trying to add a column to the react table using an add column button, but I am a little confused on how to implement this. I want to be able to add a column to the corresponding side that the button is clicked. Do I need to create a custom function and add it to my columns array or is there an easier way to implement this?
Here is the code.
/* eslint-disable jsx-a11y/click-events-have-key-events */
/* eslint-disable jsx-a11y/no-static-element-interactions */
/* eslint-disable guard-for-in */
/* eslint-disable no-restricted-syntax */
/* eslint-disable react/jsx-props-no-spreading */
import React, { useEffect, useState } from 'react';
import styled from 'styled-components';
import { useTable } from 'react-table';
import data from '../Data/data.json';
import './Table.css';
const Styles = styled.div`
table {
border-spacing: 0;
border: 1px solid black;
width: 970px;
tr {
:last-child {
td {
border-bottom: 0;
height: 500px;
}
}
}
th,
td {
margin: 0;
padding: 0.5rem;
border-bottom: 1px solid black;
border-right: 1px solid black;
:last-child {
border-right: 0;
}
}
}
`;
const HarveyBall = (initialValue) => {
const [value, setValue] = useState(initialValue);
const onClick = () => {
if(value === 'Empty'){
setValue('Quarter');
}
if(value === 'Quarter'){
setValue('Half');
}
if(value === 'Half'){
setValue('Three-Quarter');
}
if(value === 'Three-Quarter'){
setValue('Full');
}
if(value === 'Full'){
setValue('Empty');
}
};
if(value === "Empty"){
return (
<div type="button" label="Empty" className="harvey none" onClick={onClick} />
);
}
if(value === "Quarter"){
return (
<div type="button" label="Quarter" className="harvey quarters quarter" onClick={onClick} />
);
}
if(value === "Half"){
return (
<div type="button" label="Half" className="harvey quarters half" onClick={onClick} />
);
}
if(value === "Three-Quarter"){
return (
<div type="button" label="Three-Quarter" className="harvey quarters three-quarters" onClick={onClick} />
);
}
if(value === "Full"){
return (
<div type="button" label="Full" className="harvey quarters full" onClick={onClick} />
);
}
return null;
};
const defaultPropGetter = () => ({});
const EditableCell = ({
value: initialValue,
row: { index },
column: { id },
updateMyData,
}) => {
const [value, setValue] = React.useState(initialValue);
const onChange = e => {
setValue(e.target.value);
};
const onBlur = () => {
updateMyData(index, id, value);
};
React.useEffect(() => {
setValue(initialValue);
}, [initialValue]);
return id === "strategicInitiative" || index === 5 ? <textarea value={value} onChange={onChange} onBlur={onBlur} style={{ width: '100%', focus: 'none', outline: 'none', border: 'none',resize: 'none', expand: {height: '1em', width: '50%', padding: '3px'}}}/> : HarveyBall(initialValue);
};
const defaultColumn = {
Cell: EditableCell,
};
function Table({ columns, getHeaderProps = defaultPropGetter, updateMyData, }) {
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow,
} = useTable({
columns,
data,
updateMyData,
defaultColumn,
});
return (
<table {...getTableProps()}>
<thead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => column.hideHeader === false ? null : (
<th
{...column.getHeaderProps([
{
className: column.className,
style: column.style,
},
getHeaderProps(column),
])}
>
{column.render('Header')}
</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{rows.map((row) => {
prepareRow(row);
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => {
return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>;
})}
</tr>
);
})}
</tbody>
</table>
);
}
export default function MatrixTable() {
const addTasks = () => {
const taskLength = [];
for(let i = 0; i < data.length; i += 1){
for(const [key] of Object.entries(data[i])){
if(key.includes("T")){
taskLength.push(key[1]);
}
}
}
const newTaskLength = (parseInt(taskLength[taskLength.length - 1], 10) + 1) ;
for(let i = 0; i < data.length; i += 1){
data[i][`T${newTaskLength}`] = "";
}
};
const taskButton = () => (
<>
<div>Tasks</div>
<button onClick={addColumns} type='button'>Add Column</button>
</>
);
const goalButton = () => (
<>
<div>Goals</div>
<button type='button'>Add Column</button>
</>
);
const columns = React.useMemo(
() => [
{
Header: () => taskButton(),
accessor: 'tasks',
style: {
width: '255px',
height: '49px',
background: '#fdf5ed',
fontSize: '16px',
color: '#f2994a',
textAlign: 'center',
lineHeight: '49px',
},
columns: [
{
hideHeader: false,
accessor: 'T1'
},
{
hideHeader: false,
accessor: 'T2'
},
{
hideHeader: false,
accessor: 'T3'
},
{
hideHeader: false,
accessor: 'T4'
},
{
hideHeader: false,
accessor: 'T5'
},
]
},
{
Header: "Strategic Inititiatives",
accessor: "strategicInitiative ",
style: {
color: '#323b3e',
width: '460px',
height: '49px',
background: '#f2f2f2',
textAlign: 'center',
lineHeight: '49px',
},
columns: [
{
hideHeader: false,
accessor: 'strategicInitiative'
}
]
},
{
Header: goalButton(),
accessor: 'goals',
style: {
color: '#56ccf2',
width: '255px',
height: '49px',
background: '#f8fcfe',
textAlign: 'center',
lineHeight: '49px',
},
columns: [
{
hideHeader: false,
accessor: 'G1'
},
{
hideHeader: false,
accessor: 'G2'
},
{
hideHeader: false,
accessor: 'G3'
},
{
hideHeader: false,
accessor: 'G4'
},
{
hideHeader: false,
accessor: 'G5'
}
]
},
],
[]
);
const addColumns = () => {
for(let i = 0; i < columns.length; i += 1) {
if(columns[i].accessor === "tasks"){
console.log(columns[i]);
columns[i].columns.push({
hideHeader: false,
accessor: 'T6'
});
}
}
};
addColumns();
const [, setData] = useState(data);
useEffect(() => {
setData(data);
}, [data]);
const updateMyData = (rowIndex, columnId, value) => {
setData(old =>
old.map((row, index) => {
if (index === rowIndex) {
return {
...old[rowIndex],
[columnId]: value,
};
}
return row;
})
);
};
return (
<Styles>
<Table columns={columns} data={data} updateMyData={updateMyData}/>
</Styles>
);
}
I would imagine that modifying the array columns which stores the data which the table uses to render, would be the correct solution. Once columns is updated, your table should re-render which will then include the updated column.
Yeah, changing columns array(not by mutation, but by setting columns prop to new required array) is the best way to go.
I'm trying to build a submenu inside a main menu with React-select, it should be something like this:
When hovering over an option from the main menu, it triggers the submenu to open at the side.
Is there a way to do this using react-select? I couldn't find any example or documentation on this, is there a function like ```optionOnMouseover`` for this? Thank you in advance!
const options = [
{ value: 'chocolate', label: 'Chocolate' },
{ value: 'strawberry', label: 'Strawberry' },
{ value: 'vanilla', label: 'Vanilla' },
];
...
<Select
value={...}
onChange={...}
options={options}
/>```
This is on click, but if you need on hover,
just modify it
import React, { useState } from "react";
import ReactDOM from "react-dom";
import Select, { components } from "react-select"
const CustomOption = (props) => {
const [submenu, setSubmenu] = useState(false)
const [height, setHeight] = useState(0)
const handleOption = (e) => {
if(submenu) {
setSubmenu(false)
} else {
setHeight(e.clientY)
setSubmenu(true)
}
}
const handleSubOption = (e) => {
console.log('clicked')
}
const { data } = props;
return data.custom ? (
<>
<div onClick={handleOption} className="customs">
{data.label} <span className="caret"/>
{
submenu && (
<div className="dropdown-submenu">
<div className="drops" onClick={handleSubOption}>
Test dropdown 1
</div>
<div className="drops" onClick={handleSubOption}>
Test dropdown 2
</div>
<div className="drops" onClick={handleSubOption}>
Test dropdown 3
</div>
</div>
)
}
</div>
<style jsx>{`
.customs {
height: 36px;
padding: 8px;
position: relative;
}
.drops {
height: 36px;
padding: 8px;
}
.customs:hover, .drops:hover {
background-color: #17cf76;
}
.dropdown-submenu {
position: fixed;
top: ${height - 10}px;
left: 410px;
min-height: 36px;
overflow: auto;
border: 1px solid hsl(0,0%,80%);
border-radius: 4px;
color: #212529;
}
`}</style>
</>
) : (
<components.Option {...props} />
);
};
const options = [
{ custom: true, label: "I'm a custom link", value: "cust" }
];
function App() {
return (
<>
<Select classNamePrefix="category-select" className="w-30" components={{ Option: CustomOption }} options={options} />
<style jsx global>{`
* {
font-family: sans-serif;
text-align: center;
}
.w-30 {
width: 30% !important;
}
`}</style>
</>
)
}
export default App