hello iam following mosh hamedani course at some point i got stuck in uploading data in table
this is my table where title and genre is uploading where in stock and rate these are number not string are not uploading here is my table body
class TableBody extends Component {
render() {
const {data,columns} = this.props
console.log({data,columns})
return ( <tbody>
{data.map(item => <tr key={item._id}>
{columns.map(column => <td key={item._id + (column.path || column.key)}>{_.get(item,column.path)}</td>)}
</tr>
)}
</tbody>
);
}
}
data and columns are coming from movietable component here is the code
class MovieTable extends Component {
columns =[
{ path:'title',label:'Title'},
{ path:'genre.name',label:'Genre'},
{ path:'numberInstock',label:'stock'},
{ path:'dailyReantalRate',label:'Rate'},
{ key: 'like' },
{key: 'delete' }
];
render() {
const {movies, onDelete,onSort ,onLike,sortColumn,onAdd,deleted} = this.props;
return (
<table className="table">
<TableHeader columns={this.columns} sortColumn={sortColumn} onSort={onSort}/>
<TableBody data={movies} columns={this.columns}/>
<tbody>
{movies.map((movie) => (
<tr key={movie._id}>
<td>{movie.title}</td>
<td>{movie.genre.name}</td>
<td>{movie.numberInStock}</td>
<td>{movie.dailyRentalRate}</td>
<td>
{" "}
<Like
liked={movie.liked}
onClick={() => onLike(movie)}
/>{" "}
</td>
<td
onClick={() => onDelete(movie._id)}
className="btn btn-danger btn-outline-warning btn-sm active "
>
Remove
</td>
</tr>
))}
</tbody>
<tbody>
{deleted.map((movie) => (
<tr key={movie._id}>
<td>{movie.title}</td>
<td>{movie.genre.name}</td>
<td>{movie.numberInStock}</td>
<td>{movie.dailyRentalRate}</td>
<td>
{" "}
<Like />{" "}
</td>
<td
onClick={() => onAdd (movie._id)}
className="btn btn-danger btn-outline-primary btn-sm active "
>
ADD
</td>
</tr>
))}
</tbody>
</table>
);
}
}
movies from props coming from its parent movies component here is movies component code
class Movies extends Component {
state = {
movies:[],
deleted: [],
genres:[],
pageSize: 9,
currentPage:1,
sortColumn:{
path:'title',
order:'asc'
}
};
componentDidMount(){
const genres =[{ _id:"",name:'All Genres'},...getGenres()]
this.setState({
movies:getMovies(),
genres
})
}
handleDelete = (_id) => {
const movie = this.state.movies.find((x) => x._id === _id);
this.setState({ deleted: [...this.state.deleted, movie] });
this.setState({ movies: this.state.movies.filter((x) => x._id !== _id) });
};
handleLike = (m) => {
const movies = [...this.state.movies];
const index = movies.indexOf(m);
movies[index] = { ...movies[index] };
movies[index].liked = !movies[index].liked;
this.setState({ movies });
};
handleReinstate = (_id) => {
const movie = this.state.deleted.find((movie) => movie._id === _id);
this.setState({ movies: [...this.state.movies, movie] });
this.setState({
deleted: this.state.deleted.filter((movie) => movie._id !== _id),
});
};
handleGenreSelect = genre => {
this.setState({selectedGenre:genre, currentPage:1})
}
handleSort= sortColumn =>{
this.setState({sortColumn});
}
render() {
const { pageSize,currentPage,sortColumn,selectedGenre,movies:allMovies,deleted} = this.state;
const filtered = selectedGenre && selectedGenre._id ? allMovies.filter(m=>m.genre._id === selectedGenre._id ): allMovies;
const sorted = _.orderBy(filtered, [sortColumn.path],[sortColumn.order]);
const movies = paginate(sorted,currentPage,pageSize)
return (
<div className="row">
<div className="col-2">
<ListGroup items={this.state.genres} selectedItem={this.state.selectedGenre} onItemSelect={this.handleGenreSelect}/>
</div>
<div className="col">
<div className={this.getbadgesClasses()}> <p>there are {filtered.length} movies in our data base</p> </div>
<MovieTable
movies={movies}
onSort={this.handleSort}
onDelete={this.handleDelete}
onLike={this.handleLike}
deleted={deleted}
onAdd={this.handleReinstate}/>
<Pagination
itemCount={filtered.length}
pageSize={pageSize}
sortColumn={sortColumn}
onPageChange={this.handlePageChange}
currentPage={currentPage}
/>
</div>
</div>
);
}
getbadgesClasses() {
let classes = " badge m-2 badge-";
classes += this.state.movies.length === 0 ? "warning" : "primary";
return classes;
}
handlePageChange = (page) => {
this.setState({currentPage: page})
};
}
this is my console.log
i have give aerong path to Columns array its like spelling mistake in path
Related
What I'm trying to pass true/false in another component. The user has the possibility to add languages(max2). When the user adds 2 same languages, the validation error will be shown, which to do that I have used some() method which returns true or false.
I tried it with ```localStorge``, but it didn't work.
import React from "react";
export default class AddLanguage extends React.Component {
constructor(props) {
super(props);
this.state = {
message: "",
items: [],
hasError: ""
};
}
updateMessage(event) {
this.setState({
message: event.target.value
});
}
handleClick() {
var items = this.state.items;
items.push(this.state.message);
this.setState({
items: items,
message: ""
});
}
handleItemChanged(i, event) {
const items = event.target.value;
console.log("items", items);
this.setState((prev) => {
const currList = prev.items;
console.log("currList", currList);
const isDuplicate = currList.some(
(lang, idx) => idx !== i && lang) === items
);
if (isDupliacte) {
return { ...prev, hasError: "A BIG ERROR" };
} else {
currList[i] = items;
return { ...prev, items: currList };
}
});
}
handleItemDeleted(i) {
var items = this.state.items;
items.splice(i, 1);
this.setState({
items: items
});
}
renderRows() {
var context = this;
return this.state.items.map(function (o, i) {
return (
<tr key={"item-" + i}>
<td>
<div>
<input
type="text"
value={o}
autoComplete="off"
onChange={context.handleItemChanged.bind(context, i)}
/>
</div>
{this.state.hasError && (
<div>
<label></label>
<div>
<svg
xmlns="http://www.w3.org/2000/svg"
className="inline-block mr-2 h-5 w-5"
viewBox="0 0 20 20"
fill="currentColor"
>
</svg>{" "}
{this.state.hasError}
{""}
</div>
</div>
)}
</td>
<td >
<button
type="button"
onClick={context.handleItemDeleted.bind(context, i)}
>
Delete
</button>
</td>
</tr>
);
}, this);
}
render() {
return (
<div>
<div>
<table>
<thead">
<tr>
<th
>
Button
</th>
<th
>
Info
</th>
<th
>
ACTION
</th>
</tr>
</thead>
<tbody>
{this.renderRows()}
</tbody>
</table>
</div>
<div>
<button
className="btn-main"
disabled={this.state.items.length >= 2}
onClick={this.handleClick.bind(this)}
>
<PlusSmIcon />
Add
</button>
</div>
</div>
);
}
}
What I want to pass to the other component is isDuplicate (which might be true/false to another component.
i have created a fuction in which onClick i delete movie but I also want to add a add button by which clicking on add button i get my deleted movie back
here is my code
class Movies extends Component {
state = {
movies: getMovies(),
};
handleDelete=(movi)=>{
const movies = this.state.movies.filter(m=> m._id !== movi._id)
this.setState({movies})
}
render() {
return (
<table className="table">
<thead>
<tr>
<th>Title</th>
<th>Genre</th>
<th>Stock</th>
<th>Rate</th>
<th></th>
</tr>
</thead>
<tbody>
{this.state.movies.map((movie) => (
<tr key={movie._id}>
<td >{movie.title}</td>
<td >{movie.genre.name}</td>
<td >{movie.numberInStock}</td>
<td >{movie.dailyRentalRate}</td>
<td onClick={()=>this.handleDelete(movie)} className="btn btn-danger btn-outline-warning btn-sm active ">Remove</td>
</tr>
))}
</tbody>
</table>
);
}
}
You need to somehow keep track of the movies that you are deleting so that you can reinstate them... 3 Components (App - parent, Movie & Deleted)
Here is your App:
export default class App extends Component {
state = { movies: getMovies(), deleted: [] };
handleDelete = id => {
const movie = this.state.movies.find(movie => movie.id === id);
this.setState({ deleted: [...this.state.deleted, movie] });
this.setState({
movies: this.state.movies.filter(movie => movie.id !== id)
});
};
handleReinstate = id => {
const movie = this.state.deleted.find(movie => movie.id === id);
this.setState({ movies: [...this.state.movies, movie] });
this.setState({
deleted: this.state.deleted.filter(movie => movie.id !== id)
});
};
render() {
return (
<div>
<h1>Movies</h1>
{this.state.movies.map(movie => {
return (
<Movie
key={movie.id}
movie={movie}
handleDelete={this.handleDelete}
/>
);
})}
<hr />
<h1>Deleted</h1>
{this.state.deleted.map(movie => {
return (
<Deleted
key={movie.id}
movie={movie}
handleReinstate={this.handleReinstate}
/>
);
})}
</div>
);
}
}
Here is your Movie:
export default function Movie({ movie, handleDelete }) {
return (
<div>
<h4>{movie.title}</h4>
<button onClick={() => handleDelete(movie.id)}>Delete</button>
</div>
);
}
Here is your Deleted / Reinstate:
export default function Deleted({ movie, handleReinstate }) {
return (
<div>
<h4>{movie.title}</h4>
<button onClick={() => handleReinstate(movie.id)}>Reinstate</button>
</div>
)
}
Here is a link to a live demo: https://stackblitz.com/edit/react-umffju?file=src%2FApp.js
For this type of problem, here’s what you could do. Store the deleted movies in state with something like this:
This.state={
currentMovies: [list of movies],
deletedMovies: [list of movies]
}
Have an array that stores Json objects like your movies. Then have a function for storing movies that have been deleted:
const deleteMoviesArray=[]
deleteMovie(movieData){
deleteMoviesArray.push(movieData);
This.setState({
deletedMovies: deletedMoviesArray
})
};
Now you have stored your deleted movies. To retrieve your deleted movies, you might use a drop down box something like this:
<select>
{
This.state.deletedMovies.map(data =>(
<option> {movie.title}</option>
))
}
</select>
And once you select one, do a similar thing to what you did with deleted movies, add a movie back to an array of available movies.
If you need your list of deleted movies to persist past a page refresh, you might consider storing that data in session storage:
window.sessionStorage.setItem(‘deletedMovieArray’, [list of movie objects])
And get them
window.sessionStorage.getItem(‘deletedMovieArray’)
I'm trying to display data after fetching it, but that does not work :
import React, { Component } from "react";
import { Table, Button, ButtonToolbar } from "react-bootstrap";
const URL = "http://localhost:51644/api/";
let passedAthleteId = 0;
let passedAthleteSessionId = 0;
class AthleteTrainingSession extends Component {
constructor(props) {
super(props);
this.state = {
athleteTrainingSession: [],
discussions: [],
warmups: [],
workouts: [],
stretchings: [],
};
}
componentDidMount() {
this.fetchAthleteTrainingSession();
}
componentDidUpdate() {
this.fetchAthleteTrainingSession();
}
fetchAthleteTrainingSession = () => {
fetch(URL + `Coaches/4/Athletes/1/AthleteSessions/4`)
.then((response) => response.json())
.then((data) => {
this.setState({
athleteTrainingSession: data,
});
});
};
render() {
const {
athleteTrainingSession,
discussions,
warmups,
workouts,
stretchings,
} = this.state;
passedAthleteId = this.props.match.params.athleteId;
passedAthleteSessionId = this.props.match.params.athleteSessionId;
this.discussions = this.state.athleteTrainingSession.Discussions;
this.warmups = this.state.athleteTrainingSession.Warmups;
this.workouts = this.state.athleteTrainingSession.Workouts;
this.stretchings = this.state.athleteTrainingSession.Stretchings;
console.log(athleteTrainingSession);
console.log(this.warmups);
return (
<React.Fragment>
<div>
<h2 className="mt-2">
Programme d'entraînement :{" "}
{athleteTrainingSession.TrainingProgramName}
</h2>
<h4>
Séance d'entraînement : {athleteTrainingSession.TrainingSessionName}
</h4>
</div>
<div>
<ButtonToolbar>
<Button variant="primary">Ajouter</Button>
<Button variant="secondary">Discussion</Button>
</ButtonToolbar>
<h4>Échauffement</h4>
<Table className="mt-4" striped bordered hover size="sm">
<thead>
<tr className="d-flex">
<th className="col-6">Exercice</th>
<th className="col-6">Options</th>
</tr>
</thead>
<tbody>
{warmups.map((warm) => (
<tr className="d-flex" key={warm}>
<td className="col-6">{warm.ExerciseName}</td>
<td className="col-6">
<ButtonToolbar>
<Button className="mr-2" variant="info">
Modifier
</Button>
<Button className="mr-2" variant="danger">
Supprimer
</Button>
</ButtonToolbar>
</td>
</tr>
))}
</tbody>
</Table>
</div>
</React.Fragment>
);
}
}
export default AthleteTrainingSession;
athleteTrainingSession contains the fetched data, and warmups is a sub-object for athleteTrainingSession.
When I console.log(warmups), I can see that it does contain data, but I cannot display it in the table.
athleteTrainingSession contains the fetched data, and warmups is a sub-object for athleteTrainingSession.
When I console.log(warmups), I can see that it does contain data, but I cannot display it in the table.
I think you have misconception of using state in component.
You're able to console the warmups because in your code you console.log(this.warmups), but you render the map with this.state.warmups
you should setState all of the data that you get from fetch, i.e:
fetchAthleteTrainingSession = () => {
fetch(URL + `Coaches/4/Athletes/1/AthleteSessions/4`)
.then((response) => response.json())
.then((data) => {
this.setState({
athleteTrainingSession: data,
warmups: data.Warmups,
workouts: data.Workouts,
discussions: data.Discussions,
stretchings: data.Stretchings,
});
});
};
by doing this way, now you can access the warmups data from this.state.warmups then render it
render() {
const {
athleteTrainingSession,
discussions,
warmups,
workouts,
stretchings,
} = this.state;
return (
<React.Fragment>
...
{warmups.map((warm) => (
<tr className="d-flex" key={warm}>
<td className="col-6">{warm.ExerciseName}</td>
<td className="col-6">
<ButtonToolbar>
<Button className="mr-2" variant="info">
Modifier
</Button>
<Button className="mr-2" variant="danger">
Supprimer
</Button>
</ButtonToolbar>
</td>
</tr>
))}
...
</React.Fragment>
)
}
The grid before sorting is as follows:
Now I am going to sort it with Patient ID
Now when I check the Patient ID: 936447 which is in last position after sorting the grid returns to it's original ordering.
But I want the sorted grid even after checking the checkbox/ selecting a row.
This the code for displaying the grid and sorting the grid.
class App extends Component {
constructor(props) {
super(props);
this.state = {
order: {},
orderby: '',
printQueueList: props.printQueueList && props.printQueueList,
};
this.sort = this.sort.bind(this);
}
componentWillReceiveProps(nextProps) {
if (this.state.printQueueList != nextProps.printQueueList)
this.setState({ printQueueList: nextProps.printQueueList && nextProps.printQueueList });
}
sort(event) {
const { order } = this.state;
let { printQueueList } = this.props;
var gridData = printQueueList;
order[event.target.id] = !order[event.target.id];
gridData = _.orderBy(gridData, (o) => typeof o[event.target.id] === 'string' ? o[event.target.id].trim().toLowerCase() : o[event.target.id], order[event.target.id] ? 'asc' : 'desc');
this.setState({
orderby: event.target.id,
printQueueList: gridData,
order
});
}
render() {
return (
<div className="App">
<table >
<thead >
<tr >
<th id="select" >
<Checkbox
input={{
name: 'selectAll',
onChange: //function
value: allSelected
}}
/>
<label htmlFor="SelectAll" >Select All</label>
</th>
<th id="PatientID" onClick={this.sort}>Patient ID {order.PatientID ? <i id="PatientID" className="fa fa-sort-asc" /> : <i id="PatientID" className="fa fa-sort-desc" />}</th>
<th id="DocType" onClick={this.sort}>Type {order.DocType ? <i id="DocType" className="fa fa-sort-asc" /> : <i id="DocType" className="fa fa-sort-desc" />}</th>
</tr>
</thead>
<tbody >
printQueueList && printQueueList.map((Queue, i) => {
return (
<tr key={Queue.PrintQueueID}
onClick={() => onSelectPrintQueueGrid(Queue.PrintQueueID)}>
<td >
<Checkbox
input={{
name: Queue.PrintQueueID,
onChange: //function
value: selectedPrintQueueList.indexOf(Queue.PrintQueueID) !== -1,
}}
/>
</td>
<td className="dashboard_table-cell" title={'Patient ID:' + Queue.PatientID}>{Queue.PatientID}</td>
<td className="dashboard_table-cell" title={'Type:' + Queue.DocType}>{Queue.DocType}></td>
</tr>)
}
)
</tbody>
</table>
</div>
)
}
}
const mapStateToProps = state => {
return {
printQueueList: state.myDashboardReducer.printQueueList,
};
};
const mapDispatchToProps = dispatch => {
return {
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(App);
Since componentWillReceiveProps(nextProps) updates the state with the newProps, the array printQueueList gets updated. For that reason before updating with newProps, I checked whether the array is sorted or not.
If it isn't sorted, update printQueueList with newProps.
componentWillReceiveProps(nextProps) {
if(_.isEmpty(this.state.order)){
if (this.state.printQueueList != nextProps.printQueueList)
this.setState({ printQueueList: nextProps.printQueueList && nextProps.printQueueList });
}
}
I am having a List of Jobs with Approve button.
Expected Result
Whenever the Approve button next to a Job is clicked, the Job should be approved and the button text should say Approved.
Original Outcome
The text of all the buttons gets changed to Approved, but only a single Job gets approved, i.e. the job the was actually approved. Also the text stays approved for all the jobs until the page is refreshed.
export default class ProfilePage extends Component {
constructor() {
super();
this.state = {
allJobs: [],
loading: true,
newLoading: false,
valueApprove: "Approve",
_id: ""
};
this.handleApproveJob = this.handleApproveJob.bind(this);
}
componentDidMount() {
var apiUrl = `http://localhost:5000/admin/pendingJobs`;
fetch(apiUrl)
.then(response => {
return response.json();
})
.then(data => {
let allJobsFromApi = data.PendingJobs.map(job => {
return {
jobmainid: job._id,
companyName: job.companyNane,
contactPerson: job.contactPerson,
jobTitle: job.jobTitle,
jobDescription: job.description,
jobCategory: job.category.name,
jobDuration: job.duration,
descriptionLink: job.descriptionLink,
status: job.status
}
})
this.setState({ allJobs: allJobsFromApi, loading: false });
})
.catch(error => {
console.log(error);
})
}
handleApproveJob(e) {
this.setState({
newLoading: true
})
e.preventDefault();
var jobId = e.target.getAttribute('jobId');
console.log(jobId);
const job = {
approvedJobId: jobId
};
approveJob(job).then((res, err) => {
if (res) {
this.setState({
newLoading: false,
valueApprove: "Approved"
})
} else {
this.setState({
loading: false,
message: "some error occured"
})
}
})
}
render() {
const { newLoading, valueApprove } = this.state;
return (
<div className="tile-body">
{loading ? <div className="col-md-4 offset-md-4"><img src=
{LoadingSpinner} /></div> : <table
className="table table-hover table-bordered table-responsive"
id="sampleTable"
style={{ border: "none" }}
>
<thead>
<tr>
<th>Company Name</th>
<th>Contact Person At Company</th>
<th>Job Title</th>
<th>Job Description</th>
<th>Job Description Link</th>
<th>Category</th>
<th>Duration</th>
<th>Edit</th>
<th>Approve</th>
</tr>
</thead>
<tbody>
{this.state.allJobs.map((job) =>
<tr key={job.jobmainid}>
<td>{job.companyName}</td>
<td>{job.contactPerson}</td>
<td>{job.jobTitle}</td>
<td>{job.jobDescription}</td>
<td>
{job.descriptionLink}
</td>
<td>{job.jobCategory}</td>
<td>{job.jobDuration}</td>
<td>
<Link to={"/admin/editJob/" + job.jobmainid}>
<button className="btn btn-warning">Edit</button>
</Link>
</td>
<td>
<button
type="submit"
className="btn btn-success"
jobId={job.jobmainid}
onClick={this.handleApproveJob}
>
{ newLoading ? <ButtonLoading /> : valueApprove }
</button>
</td>
</tr>
)}
</tbody>
</table>}
</div>
The code for aproveJob() function
//Approve Job
export const approveJob = job => {
return axios.post("http://localhost:5000/admin/approveJob", {
_id: job.approvedJobId
})
.then(response => {
return response.data;
})
.catch(err => {
console.log(err);
});
}
Right now you are only storing a single variable with the approved state. Instead we need one per button.
You could do something like the below code.
After getting the array jobs from the server inject a value approved: false
On button click find and update that item in your state with approved: true
I'm not certain the code below runs but it will point you in the right direction.
import React, { Component } from 'react'
import { Link } from 'react-router-dom'
export const approveJob = (job) => {
return fetch('http://localhost:5000/admin/approveJob', {
_id: job.approvedJobId
})
.then((response) => {
return response.data
})
.catch((err) => {
console.log(err)
})
}
export default class ProfilePage extends Component {
constructor(props) {
super(props)
this.state = {
allJobs: [],
loading: true,
newLoading: false
}
this.handleApproveJob = this.handleApproveJob.bind(this)
}
componentDidMount() {
const apiUrl = `http://localhost:5000/admin/pendingJobs`
fetch(apiUrl)
.then((response) => {
return response.json()
})
.then((data) => {
const allJobsFromApi = data.PendingJobs.map((job) => {
return {
jobmainid: job._id,
companyName: job.companyNane,
contactPerson: job.contactPerson,
jobTitle: job.jobTitle,
jobDescription: job.description,
jobCategory: job.category.name,
jobDuration: job.duration,
descriptionLink: job.descriptionLink,
status: job.status,
approved: false
}
})
this.setState({ allJobs: allJobsFromApi, loading: false })
})
.catch((error) => {
console.log(error)
})
}
handleApproveJob(e, index) {
e.preventDefault()
this.setState({
newLoading: true
})
const jobId = e.target.getAttribute('jobId')
console.log(jobId)
const job = {
approvedJobId: jobId
}
approveJob(job).then((res) => {
if (res) {
const newAllJobs = this.state.allJobs
newAllJobs[index].approved = true
this.setState({
newLoading: false,
valueApprove: 'Approved',
allJobs: newAllJobs
})
} else {
this.setState({
loading: false,
message: 'some error occured'
})
}
})
}
render() {
const { loading, newLoading, valueApprove, allJobs } = this.state
return (
<div className="tile-body">
{loading ? (
<div className="col-md-4 offset-md-4">
<img src={LoadingSpinner} />
</div>
) : (
<table
className="table table-hover table-bordered table-responsive"
id="sampleTable"
style={{ border: 'none' }}
>
<thead>
<tr>
<th>Company Name</th>
<th>Contact Person At Company</th>
<th>Job Title</th>
<th>Job Description</th>
<th>Job Description Link</th>
<th>Category</th>
<th>Duration</th>
<th>Edit</th>
<th>Approve</th>
</tr>
</thead>
<tbody>
{allJobs.map((job, index) => (
<tr key={job.jobmainid}>
<td>{job.companyName}</td>
<td>{job.contactPerson}</td>
<td>{job.jobTitle}</td>
<td>{job.jobDescription}</td>
<td>
<a href={job.descriptionLink} target="_blank">
{job.descriptionLink}
</a>
</td>
<td>{job.jobCategory}</td>
<td>{job.jobDuration}</td>
<td>
<Link to={'/admin/editJob/' + job.jobmainid}>
<button className="btn btn-warning">Edit</button>
</Link>
</td>
<td>
<button
type="button"
className="btn btn-success"
jobId={job.jobmainid}
onClick={(e) => this.handleApproveJob(e, index)}
>
{newLoading ? <ButtonLoading /> : valueApprove}
</button>
</td>
</tr>
))}
</tbody>
</table>
)}
</div>
)
}
}
try this.
handleApproveJob(e) {
this.setState({
newLoading: true
});
e.preventDefault();
var jobId = e.target.getAttribute('jobId');
console.log(jobId);
const job = {
approvedJobId: jobId
};
let self = this;
approveJob(job).then((res, err) => {
if (res) {
self.setState({
newLoading: false,
valueApprove: "Approved"
})
} else {
self.setState({
loading: false,
message: "some error occured"
})
}
})
}
<button type="submit" className="btn btn-success" jobId={job.jobmainid} onClick={this.handleApproveJob}>
{ this.state.newLoading ? <ButtonLoading /> : this.state.valueApprove }
</button>
I hope I've been there for you. Let me know.
Three things are there.
you need to add approve: false to every item in the jobs
On clicking approve button of any job, you need to pass index of that job in the approveJob(index) function.
Depending on the index value (which was passed in approveJob(index)) you need to updated the particular job in the job array in the state.
Just update the render function code for approve button, as you need change text on clicking button
render() {
const { loading, newLoading, valueApprove, allJobs } = this.state
return (
<div className="tile-body">
{loading ? (
<div className="col-md-4 offset-md-4">
<img src={LoadingSpinner} />
</div>
) : (
<table
className="table table-hover table-bordered table-responsive"
id="sampleTable"
style={{ border: 'none' }}
>
<tbody>
{allJobs.map((job, index) => (
<tr key={job.jobmainid}>
<td>
<button
type="button"
className="btn btn-success"
jobId={job.jobmainid}
onClick={(e) => this.handleApproveJob(e, index)}
>
{job.approved ? "approved" : "approve"}
</button>
</td>
</tr>
))}
</tbody>
</table>
)}
</div>
)
}
}