The code that I posted below is the API request from which I make a table. This table has 4 columns: id, userid, title. I want to understand how I can sort by userid and title, as shown in the photo. It would be great if the steps were described in detail.
I'm trying to group the tab as shown in the photo, but I can't.
Can you suggest/show me how to do this?
Also wanted to know how to reset the group value of a column?
I will be grateful for any help.
My code:
import React from "react";
import "./GroupByUserID.css";
import { Link } from "react-router-dom";
export default class GroupByUserID extends React.Component {
// Constructor
constructor(props) {
super(props);
this.state = {
items: [],
};
}
componentDidMount = () => {
this.apiFetch();
};
//Fetch data from API
apiFetch = () => {
return fetch("https://jsonplaceholder.typicode.com/todos")
.then((res) => res.json())
.then((json) => {
this.setState((prevState) => {
return { ...prevState, items: json };
});
});
};
// Sort UserID
setSortedItemsUserID = () => {
const { items } = this.state;
const sortedUserID = items.sort((a, b) => {
if (a.userId < b.userId) {
return items.direction === "ascending" ? -1 : 1;
}
if (a.userId > b.userId) {
return items.direction === "ascending" ? 1 : -1;
}
return 0;
});
console.log(sortedUserID);
this.setState((prevState) => {
return { ...prevState, items: sortedUserID };
});
};
render() {
const { items } = this.state;
return (
<div>
<h1>Home Page</h1>
<table>
<thead>
<tr>
<th>
<Link target="self" to="/">
View Normal
</Link>
</th>
<th>Group By UserID</th>
</tr>
</thead>
<thead>
<tr>
<th>
User ID
<button
type="button"
onClick={() => this.setSortedItemsUserID()}
>
⬇️
</button>
</th>
<th>Title</th>
</tr>
</thead>
<tbody>
{items.map((item) => (
<tr key={item.userId + item.title}>
<td>{item.userId}</td>
<td>{item.title}</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
}
Related
I am trying to use this.remove() in order to remove an item from a JPA repository, but for some reason it does not work. Below is the code from the JavaScript page that contains the delete button, with the specific line in bold:
import React, { Component } from 'react';
import '../css/TaskList.css';
import { Button, ButtonGroup, Container, Table } from 'reactstrap';
import Select from "react-select/creatable";
import AppNavbar from './AppNavbar';
import { Link } from 'react-router-dom';
class TaskList extends Component {
constructor(props) {
super(props);
this.state = {tasks: [], isLoading: true};
this.remove = this.remove.bind(this);
}
componentDidMount() {
fetch('/tasks')
.then(response => response.json())
.then(data => this.setState({tasks: data, isLoading: false}));
}
async remove(id) {
await fetch(`/tasks/${id}`, {
method: 'DELETE',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
}).then(() => {
let updatedTasks = [...this.state.tasks].filter(i => i.id !== id);
this.setState({tasks: updatedTasks});
});
}
render() {
const {tasks, isLoading} = this.state;
//if waiting for tasks to fetch
if (isLoading) {
return <p>Loading...</p>;
}
//options for the sort select menu
const options = [
{value: 'priority', label: 'Priority'},
{value: 'type', label: 'Type'},
{value: 'class', label: 'Class'},
{value: 'date', label: 'Due Date'}
]
//method to be called when a new sort selection is made
const handleSortSelectChange = (option) => {
let updatedTasks;
switch (option.value) {
case 'priority':
updatedTasks = tasks.sort((a, b) => b.priority - a.priority);
break;
case 'date':
updatedTasks = tasks.sort((a, b) => a.dueDate - b.dueDate);
break;
case 'class':
//TODO implement sort by class
console.log('Sort by class');
updatedTasks = tasks;
break;
case 'type':
updatedTasks = tasks.sort((a, b) => b.typeID - a.typeID);
break;
default:
updatedTasks = tasks.sort((a, b) => a.dueDate - b.dueDate);
}
this.setState({tasks: updatedTasks});
}
//component that maps all tasks to <tr> elements
const taskList = tasks.map(task => {
const date = task.dueDate;
return (
<tr key={task.id} onClick={"/tasks/" + task.id}>
<td style={{whiteSpace: 'nowrap'}}><a href={"/tasks/" + task.id}>{task.name}</a></td>
<td className='task-priority'>{getPriorityString(task.priority)}</td>
<td>{task.courseID}</td>
<td>{task.type}</td>
<td>{date}</td>
<td>
** <ButtonGroup>
<Button size="sm" color="danger" onClick={() => this.remove(task.id)}>Delete</Button>**
</ButtonGroup>
</td>
</tr>
);
});
return (
<div>
<AppNavbar/>
<Container fluid>
<h3 className='m-2'>Tasks</h3>
<div id="list-top" className="m-2">
<Button color="success" tag={Link} to="/tasks/new">Add Task</Button>
</div>
<div id="list-sort" className="m-2">
<Select className='m-2' options={options} onChange={handleSortSelectChange}/>
</div>
<div id="list-top" className="m-2">
<h5 className='m-2'>Sort By</h5>
</div>
<Table className="m-2">
<thead>
<tr>
<th width="30%">Name</th>
<th width="10%">Priority</th>
<th width="20%">Class</th>
<th width="10%">Type</th>
<th width="20%">Due Date</th>
<th width="10%"></th>
</tr>
</thead>
<tbody>
{taskList}
</tbody>
</Table>
</Container>
</div>
);
}
}
function getPriorityString(priority) {
let result = "";
let i;
for (i = 0; i < priority; i++) {
result += "!";
}
return result;
}
export default TaskList;
I've tried looking around online and at other forums to see if I am doing something wrong, but everything I have found says that this should work. Everything else works within the program, so I'm at a loss as to why this specific function does not.
This is my librarylist component in which i pass deletehandler function to delete the row from library management. I don't know which part of the code is causing the problem. Any helps/suggestions are welcome.
LibraryBookList.js
const LibraryBookList = (props) => {
const[database, setDatabase]=useState()
const deleteHandler = (bookdataId) => {
const newDatabase=[...database];
const index= database.findIndex((bookdata)=>bookdata.id===bookdataId)
newDatabase.splice(index,1)
setDatabase(newDatabase);
} ;
return (
<ul className={classes.list}>
{props.database.map((bookdata) =>
(<LibraryBook
key={bookdata.key}
id={bookdata.id}
bookname={bookdata.bookName}
author={bookdata.author}
publisher={bookdata.publisher}
pages={bookdata.pages}
serialno={bookdata.serialNo}
onSelect={deleteHandler}
/>
))}
</ul>
)};
here i pass deletehandler via props
LibraryBook.js
const LibraryBook = (props) => {
return (
<li>
<table className={classes.table}>
<tbody>
<tr className={classes.table_row}>
<td className={classes.row_data}>{props.serialno}</td>
<td className={classes.row_data}>{props.pages}</td>
<td className={classes.row_data}>{props.bookname}</td>
<td className={classes.row_data}>{props.author}</td>
<td className={classes.row_data}>{props.publisher}</td>
<td>
<button className={classes.delete_btn} onClick={(props.onSelect(props.id))}>
Delete
</button>
</td>
</tr>
</tbody>
</table>
</li>
export default LibraryBookList;
**BookData.js **
const BookData = (props) => {
const [isLoading, setIsLoading] = useState(true);
const [loadedLibrarydata, setLoadedLibrarydata] = useState();
useEffect(() => {
setIsLoading(true);
fetch(
"https://librarymanagement-70ab2-default-rtdb.firebaseio.com/database.json"
)
.then((response) => {
// console.log('response',response.json())
return response.json();
})
.then((data) => {
const database = [];
console.log("data", data);
for (const key in data) {
const bookdata = {
id: key,
...data[key],
};
database.push(bookdata);
}
setIsLoading(false);
setLoadedLibrarydata(database);
});
}, []);
if (isLoading) {
return (
<section>
<p>Loading.....</p>
</section>
);
}
return (
<section>
<h1>Book Data Base</h1>
<table className={classes.table}>
<thead>
<tr className={classes.table_row}>
<th className={classes.row_heading}>Serial No</th>
<th className={classes.row_heading}>Pages</th>
<th className={classes.row_heading}>Book Name</th>
<th className={classes.row_heading}>Author</th>
<th className={classes.row_heading}>Publisher</th>
</tr>
</thead>
</table>
{loadedLibrarydata && loadedLibrarydata.length && (
<LibraryBooklist database={loadedLibrarydata} />
)}
</section>
);
};
export default BookData;
NewDataBase.js
const NewDataBase = () => {
const history=useHistory();
const addDataHandler = (bookData) => {
console.log('bookData',bookData);
fetch(
"https://librarymanagement-70ab2-default-rtdb.firebaseio.com/database.json",
{
method: "POST",
body: JSON.stringify(bookData),
headers: {
"Content-type": "application/json",
},
}
).then(()=>{
history.replace('/')
})
};
return (
<section>
<DataBaseForm onAddNewData={addDataHandler} />
</section>
);
};
export default NewDataBase;
The code has a few issues: 1) props.onSelect(props.id) inside onClick. Instead you should give a referance to that function. 2) You didn't have anything in database state before you click delete button. That is why ... spread operator didn't work 3) You are displaying props.database instead of database state. That is way the changes didn't show up even after you deleted a bookdata. I also fixed some small issues. Now it is working perfectly:
// !! you can put all the code into one file and run for testing.
// !! I removed stylings as I didn't have the source
import {useState, useEffect} from 'react'
const LibraryBooklist = (props) => {
const[database, setDatabase]=useState(props.database)
const deleteHandler = (bookdataId) => {
const newDatabase=database.filter((bookdata)=>bookdata.id!==bookdataId);
setDatabase(newDatabase);
}
return (
<ul>
{database.map((bookdata) =>
<LibraryBook
key={bookdata.id}
id={bookdata.id}
bookname={bookdata.bookName}
author={bookdata.author}
publisher={bookdata.publisher}
pages={bookdata.pages}
serialno={bookdata.serialNo}
onSelect={deleteHandler}
/>
)}
</ul>
)};
const LibraryBook = (props) => {
const {id, onSelect} = props
return (
<li>
<table>
<tbody>
<tr>
<td>{props.serialno}</td>
<td>{props.pages}</td>
<td>{props.bookname}</td>
<td>{props.author}</td>
<td>{props.publisher}</td>
<td>
<button onClick={() => onSelect(id)}>
Delete
</button>
</td>
</tr>
</tbody>
</table>
</li>
)}
const BookData = (props) => {
const [isLoading, setIsLoading] = useState(true);
const [loadedLibrarydata, setLoadedLibrarydata] = useState();
useEffect(() => {
setIsLoading(true);
fetch(
"https://librarymanagement-70ab2-default-rtdb.firebaseio.com/database.json"
)
.then((response) => {
// console.log('response',response.json())
return response.json();
})
.then((data) => {
const database = [];
for (const key in data) {
const bookdata = {
id: key,
...data[key],
};
database.push(bookdata);
}
setIsLoading(false);
setLoadedLibrarydata(database);
});
}, []);
if (isLoading) {
return (
<section>
<p>Loading.....</p>
</section>
);
}
return (
<section>
<h1>Book Data Base</h1>
<table>
<thead>
<tr>
<th>Serial No</th>
<th>Pages</th>
<th>Book Name</th>
<th>Author</th>
<th>Publisher</th>
</tr>
</thead>
</table>
{loadedLibrarydata && loadedLibrarydata.length && (
<LibraryBooklist database={loadedLibrarydata} />
)}
</section>
);
};
export default BookData;
i am trying to sort html table by ASC and desc order but this table is not working properly its working only for first column when i put id name can you please help me for make this work sorting func by ASC and Desc. this is my code so far i tried but its not working Thanks
import React from "react";
class Th extends React.Component {
handleClick = () => {
const { onClick, id } = this.props;
onClick(id);
};
render() {
const { value } = this.props;
return <th onClick={this.handleClick}>{value}</th>;
}
}
class App extends React.Component {
state = {
users: []
};
async componentDidMount() {
const res = await fetch(
`https://run.mocky.io/v3/6982a190-6166-402e-905f-139aef40e6ef`
);
const users = await res.json();
this.setState({
users
});
}
handleSort = id => {
this.setState(prev => {
return {
[id]: !prev[id],
users: prev.users.sort((a, b) =>
prev[id] ? a[id] < b[id] : a[id] > b[id]
)
};
});
};
render() {
const { users } = this.state;
return (
<table>
<thead>
<tr>
<Th onClick={this.handleSort} id="mileage" value="Mileage" />
<Th onClick={this.handleSort} id="overall_score" value="Overall score" />
<Th onClick={this.handleSort} id="fuel_consumed" value="Fuel Consumed" />
</tr>
</thead>
<tbody>
{users.map(user => (
<tr>
<td>{user.span.mileage.value}</td>
<td>{user.span.overall_score.value}</td>
<td>{user.span.fuel_consumed.value}</td>
</tr>
))}
</tbody>
</table>
);
}
}
export default App;
To make it works you need to change a few thigs:
the setState merges new data with old one, so [id]: !prev[id] adds new property to state for each column you filter without removing old one. It's better to store column to filter in dedicated state property (e.g. sortBy).
fix sorting function to make it sorting the users by correct object properties
remove async from componentDidMount and change fetch to use then/catch instead of async/await (it makes your code more React-ish).
Use example below as an inspiration:
class App extends React.Component {
state = {
sortBy: null,
order: "ASC",
users: []
};
componentDidMount() {
fetch(`https://run.mocky.io/v3/6982a190-6166-402e-905f-139aef40e6ef`)
.then(response => response.json())
.then(users => this.setState({users}))
.catch(err => console.log('Error', err));
}
handleSort = id => {
this.setState(prev => {
const ordered = prev.users.sort((a, b) =>
prev.order === "ASC"
? a["span"][id]["value"] < b["span"][id]["value"]
: a["span"][id]["value"] > b["span"][id]["value"]
);
return {
sortBy: id,
order: prev.order === "ASC" ? "DESC" : "ASC",
users: ordered
};
});
};
render() {
const { users } = this.state;
return (
<table>
<thead>
<tr>
<Th onClick={this.handleSort} id="mileage" value="Mileage" />
<Th
onClick={this.handleSort}
id="overall_score"
value="Overall score"
/>
<Th
onClick={this.handleSort}
id="fuel_consumed"
value="Fuel Consumed"
/>
</tr>
</thead>
<tbody>
{users.map(user => (
<tr>
<td>{user.span.mileage.value}</td>
<td>{user.span.overall_score.value}</td>
<td>{user.span.fuel_consumed.value}</td>
</tr>
))}
</tbody>
</table>
);
}
}
class Th extends React.Component {
handleClick = () => {
const { onClick, id } = this.props;
onClick(id);
};
render() {
const { value } = this.props;
return <th onClick={this.handleClick}>{value}</th>;
}
}
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Keep in mind that in only works with the current data schema and fields you already have. If you want to change the fields to sort by you need to update sorting function.
Here my code to upload multi files in React JS and show these files front of the user. .I have two buttons near of the name of the files : first button name:"Delete" when the user click it all the row disappear,and that works fine. second button name: "Change" when the user click it he can upload another file, and the new file must replace the old . How can I do that ?
import React from 'react';
import '../index.css';
import './dna.css';
export default class Browse extends React.Component {
state = {
files: []
};
fileUpload = (e) => {
console.log(e.target.files);
this.setState({ files: [...e.target.files] });
};
Change(id) {
console.log('Change Function');
}
Delete(name) {
this.setState((prevState) => ({
files: prevState.files.filter((file) => file.name !== name)
}));
console.log(this.state.files.name);
}
render() {
return (
<div className='Browse'>
<label>Insert DNA Files:</label>
<input
type='file'
multiple='multiple'
id='file'
onChange={this.fileUpload}
/>
<table className='filesName'>
{this.state.files.map((file, i) => (
<tr key={i}>
- <th style={{ textAlign: 'left' }}>{file.name} : </th>
<th>
<button type='file' onClick={() => this.Change(i)}>
Change
</button>
</th>
<th>
<button onClick={() => this.Delete(file.name)}>Delete</button>
</th>
</tr>
))}
</table>
</div>
);
}
}
Please check this example:
import React from "react";
import '../index.css';
// import './dna.css';
export default class Browse extends React.Component {
constructor(props) {
super(props);
this.state = {
files: [],
changedFileIndex: -1
};
this.fileUploaderRef = React.createRef();
}
fileUpload = (e) => {
let changedFile = e.target.files[0];
let uploadedFiles = e.target.files;
if (this.state.changedFileIndex >= 0) {
this.setState(prevState => {
const list = [];
prevState.files.map((file, i) => {
if (i === prevState.changedFileIndex)
list.push(changedFile);
else
list.push(file);
});
return {
files: list,
changedFileIndex: -1,
};
});
} else if (this.state.files.length > 0) {
this.setState(prevState => {
return {files: [...prevState.files, ...uploadedFiles]}
});
} else
this.setState({files: [...e.target.files]});
};
Change(index, file) {
console.log("Change Function");
this.setState({changedFileIndex: index});
this.fileUploaderRef.current.click();
}
Delete(name) {
this.setState(prevState => {
const list = [];
prevState.files.map((file, i) => {
if (file.name !== name) {
list.push(file);
}
});
return {
files: list,
changedFileIndex: -1,
};
});
}
render() {
return (
<div className="Browse">
<label>Insert DNA Files:</label>
<input type="file" multiple="multiple" id="file" ref={this.fileUploaderRef} onChange={this.fileUpload}/>
<table className="filesName">
<tbody>
{
this.state.files.map((file, i) =>
<tr key={i}>
<th style={{textAlign: "left"}}>{file.name} :</th>
<th>
<button type="file" onClick={() => this.Change(i)}>Change</button>
</th>
<th>
<button onClick={() => this.Delete(file.name)}>Delete</button>
</th>
</tr>
)
}
</tbody>
</table>
</div>
);
}
}
I have app wrote on pure React where I make request to server and get response - category list. This list I can sort by asc-desc when I click by title table id.I needed to remake small part of my React app to Redux.
But when I remake this part to redux I have error:
Cannot read property 'sortAscDesc' of undefined - in reducer.
Also error in Table.js in line:
<th className="th-id" onClick={() => dispatch(changeSortAscDesc())}>ID <small>{sortAscDesc}</small></th>
First in my question I'll write code that I remake to Redux
and below after _______________________________ I'll write small part my app which wrote on pure React(before remake to redux) and work well.
Wrote on REDUX:
filterList.js(action):
export const changeSortAscDesc = (prev) => ({
type: "SORT_ASC_DESC",
payload: prev
});
filterList.js(reducer):
const initialState = {
sortAscDesc: "asc",
};
export function filterList(state = initialState, action) {
switch (action.type) {
case "SORT_ASC_DESC": {
const { payload } = action;
return {
...state,
sortAscDesc: payload.sortAscDesc == 'asc' ? 'desc' : 'asc'
};
}
default:
return state;
}
}
Table.js:
export default (props) => {
const sortAscDesc = useSelector(state => state.filterListReducer.sortAscDesc);
const dispatch = useDispatch();
return (
<table>
<thead>
<tr>
<th></th>
<th onClick={() => dispatch(changeSortAscDesc())}>ID <small>{sortAscDesc}</small></th>
<th>TITLE</th>
</tr>
</thead>
<tbody className="table-body">
{props.dataAttribute.map(item => (
<tr key={item.id}>
<td>{item.id} </td>
<td>{item.title} </td>
</tr>
))}
</tbody>
</table>
);}
_______________________________________________________
Wrote on pure React (before remake to redux):
Home.js:
const Home = () => {
const [value, setValue] = useState({
listCategory: [],
sortAscDesc: "asc",
});
// Here useEffect and fetch function, but I dont write it, because it not related with my question
const changeSortAscDesc = () => {
setValue((prev) => ({
...prev,
sortAscDesc: prev.sortAscDesc == 'asc' ? 'desc' : 'asc'
}));
};
return (
<div>
<Table dataAttribute={value.listCategory}
changeSortAscDesc={changeSortAscDesc}
sortAscDesc={value.sortAscDesc}
/>
</div>
);
Table.js:
export default (props) => {
const sortAscDesc = useSelector(state => state.filterListReducer.sortAscDesc);
const dispatch = useDispatch();
return (
<table>
<thead>
<tr>
<th></th>
<th onClick={props.changeSortAscDesc}>ID <small>{props.sortAscDesc}</small></th>
<th>TITLE</th>
</tr>
</thead>
<tbody className="table-body">
{props.dataAttribute.map(item => (
<tr key={item.id}>
<td>{item.id} </td>
<td>{item.title} </td>
</tr>
))}
</tbody>
</table>
);}
You are not dispatching any payload with your action -
<th onClick={() => dispatch(changeSortAscDesc(dataThatNeedsToBePassed))}>ID <small>{sortAscDesc}</small></th> //pass data as parameter
EDIT- You can make it work in this way -
const initialState = {
sortAscDesc: "asc",
};
export function filterList(state = initialState, action) {
switch (action.type) {
case "SORT_ASC_DESC": {
const { payload } = action; // no need //
return {
...state,
sortAscDesc: state.sortAscDesc == 'asc' ? 'desc' : 'asc'
};
}
default:
return state;
}
}
And you can remove payload from your action -
export const changeSortAscDesc = () => ({
type: "SORT_ASC_DESC",
payload: prev// no need //
});