Three option for displaying dynamical javascript with css - javascript

Goal:
Value 1 show css > badge-primary
Value 2 show css > badge-secondary
The rest of the value show css > badge-danger
It take place at function handleChange.
Problem:
I was only enable to use false or true in order to use css. It is only two option.
The third option should be available and how should it be solved? Any suggestoin?
Info:
*Newbie in reactjs
Stackblitz:
https://stackblitz.com/edit/react-34tdvs?
css
h1,
p {
font-family: Lato;
}
.badge-primary {
text-align: center;
color: blue;
}
.badge-danger {
font-size: 15px;
color: red;
}
.badge-secondary {
font-size: 15px;
color: rgb(0, 204, 255);
}
import React from 'react';
import './style.css';
import React, { Component } from 'react';
import axios from 'axios';
export default class App extends Component {
constructor() {
super();
this.state = {
isLoaded: false,
listData: [],
list2Data: [],
list3DataRaw: [],
list3Data: [],
value: true
};
}
componentDidMount() {
axios
.get('https://jsonplaceholder.typicode.com/comments?postId=1')
.then(response =>
this.setState({
isLoaded: true,
listData: response.data
})
);
axios.get('https://jsonplaceholder.typicode.com/users').then(response =>
this.setState({
isLoaded: true,
list2Data: response.data
})
);
axios.get('https://jsonplaceholder.typicode.com/todos').then(response =>
this.setState({
isLoaded: true,
list3DataRaw: response.data
})
);
}
handleChange = ({ target }) => {
// copy current list of Item
const list = [...this.state.list3DataRaw];
if (1 == target.value) {
this.setState({
value: false
});
}
if (1 != target.value) {
this.setState({
value: true
});
}
// filter out item being deleted
const updateList = list.filter(item => item.userId == target.value);
this.setState({
list3Data: updateList
});
};
render() {
const { isLoaded } = this.state;
const locations =
this.state.list2Data &&
this.state.list2Data.map(location => {
return { value: location.id, label: location.name };
});
const locationss =
this.state.list3Data &&
this.state.list3Data.map(location => {
return { value: location.userId, label: location.title };
});
//console.log(locations);
//console.log(locationss);
if (!isLoaded) {
return <div>Loading...</div>;
} else {
return (
<>
<select
id="selectLocation"
value={locations.value}
onChange={this.handleChange}
>
{locations.map(({ value, label }, index) => (
<option value={value}>{label}</option>
))}
</select>
<select
id="selectLocationn"
className={this.state.value ? 'badge-primary' : 'badge-danger'}
value={locationss.value}
onChange={this.handleChange}
>
{locationss.map(({ value, label }, index) => (
<option value={value}>{label}</option>
))}
</select>
<table className="table">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Email</th>
</tr>
</thead>
<tbody>
{this.state.listData &&
this.state.listData.map(item => {
return (
<tr key={item.id.toString()}>
<td>{item.id}</td>
<td>{item.name}</td>
<td>{item.email}</td>
</tr>
);
})}
</tbody>
</table>
</>
);
}
}
}

Here is the working branch,
https://stackblitz.com/edit/react-dwtfr1
I will add comments in below code so you will know what I am doing.
import React from 'react';
import './style.css';
import React, { Component } from 'react';
import axios from 'axios';
export default class App extends Component {
constructor() {
super();
// Modified state a bit to remove getting the raw data. We can get what we need when we fetch data.
this.state = {
isLoaded: false,
listData: [],
list2Data: [],
//Selected items needs to go in another state. I am selecting first item by default.
selectedlist2DataItem: 1,
selectedlist3DataItem: 1,
list3Data: []
};
}
componentDidMount() {
axios
.get('https://jsonplaceholder.typicode.com/comments?postId=1')
.then(response => {
//You set state logic was wrong. You have to bring only state and update what's new. ...this.state, is for that.
this.setState({
...this.state,
isLoaded: true,
listData: response.data
});
});
axios.get('https://jsonplaceholder.typicode.com/users').then(response =>
//Set set state issue as above one
this.setState({
...this.state,
isLoaded: true,
list2Data: response.data.map(location => {
return { value: location.id, label: location.name };
})
})
);
axios.get('https://jsonplaceholder.typicode.com/todos').then(response =>
//Set set state issue as above one
this.setState({
...this.state,
isLoaded: true,
// Moved the logic here
list3Data: response.data.map(location => {
return { value: location.userId, label: location.title };
})
})
);
}
// We are handing 2 dropdown events so we need to know which is what. That's why I added name.
handleChange = ({ target }, name) => {
if (name === 'selectLocation') {
// Selected item we need a number that's why +target.value. + makes a string to number.
this.setState({
...this.state,
selectedlist2DataItem: +target.value
});
} else {
this.setState({
...this.state,
selectedlist3DataItem: +target.value
});
}
};
render() {
const { isLoaded } = this.state;
if (!isLoaded) {
return <div>Loading...</div>;
} else {
return (
<>
<select
id="selectLocation"
value={this.state.selectedlist2DataItem}
onChange={e => this.handleChange(e, 'selectLocation')}
>
{/* maping is done on state value. value property is also using state. */}
{this.state.list2Data.map(({ value, label }, index) => (
<option value={value}>{label}</option>
))}
</select>
{/* Your class logic with values. use State for this pupose */}
<select
id="selectLocationn"
className={
this.state.selectedlist3DataItem === 1
? 'badge-primary'
: this.state.selectedlist3DataItem === 2
? 'badge-secondary'
: 'badge-danger'
}
value={this.state.selectedlist3DataItem}
onChange={e => this.handleChange(e, 'selectLocationn')}
>
{/* maping is done on state value.value property is also using state. */}
{this.state.list3Data.map(({ value, label }, index) => (
<option value={value}>{label}</option>
))}
</select>
<table className="table">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Email</th>
</tr>
</thead>
<tbody>
{this.state.listData &&
this.state.listData.map(item => {
return (
<tr key={item.id.toString()}>
<td>{item.id}</td>
<td>{item.name}</td>
<td>{item.email}</td>
</tr>
);
})}
</tbody>
</table>
</>
);
}
}
}
Result

...........Another solution:
https://stackblitz.com/edit/react-8aqbpa?

Related

setState on button click and post axios

I have this on the front end (react) right now.
import '../styles/TourPage.css';
import React, { Component } from 'react';
import axios from 'axios'
class TourPage extends Component {
constructor(props) {
super(props);
this.state = {
myData: []
}
}
componentDidMount() {
axios.get('/getResults')
.then( res => {
console.log("Res is: ", res.data)
this.setState({
myData: res.data
});
})
console.log("res.data", this.state.myData)
}
render() {
console.log("res.data", this.state.myData)
return (
<table id="customers">
<tr>
<th>siteLocation</th>
<th>Services</th>
<th>cnum</th>
</tr>
{this.state.myData.length > 0? this.state.myData.map((data, index) => (
<tr>
{/* <tr key={index}> */}
<td>{data.location}</td>
<td>{data.Services}</td>
<td>{data.cnum}</td>
<button onClick={this.click} disabled={this.state.isLoading}> Delete </button>
{/* {this.state.data} */}
{/* </tr> */}
</tr>
))
: "No Data Found"}
</table>
);
}
}
export default TourPage;
What I want to do, is on a button click, set data._id in the state, and then call Axios to post it to the Node.JS backend server, so I can update the database. Basically to delete the document. as you can see below, I tried with <a href> but that seems to be an HTML-specific thing. I also tried with the button, but I cannot figure it out. How can I do this?
I have refactored most of your code. You can pass id using an anonymous arrow function.
Do modify this to suit your needs.
import { render } from "react-dom";
import React, { Component } from "react";
import axios from "axios";
import "../styles/TourPage.css";
class TourPage extends Component {
constructor(props) {
super(props);
this.state = {
myData: [],
isLoading: true
};
}
componentDidMount() {
axios
.get("/getResults")
.then((res) => {
this.setState({
myData: res.data
});
})
.catch((error) => {
// Handle the errors here
console.log(error);
})
.finally(() => {
this.setState({
isLoading: false
});
});
}
deleteById = (id) => {
// You'll get the id here
// Delete by id code goes here
};
render() {
// You can handle the loader part here with isLoading flag. In this case No data found will be shown initially and then the actual data
let { myData, isLoading } = this.state;
return (
<table id="customers">
<tr>
<th>siteLocation</th>
<th>Services</th>
<th>cnum</th>
</tr>
{myData.length > 0
? myData.map(({ location, Services, cnum, _id }, index) => (
<tr key={index}>
<td>{location}</td>
<td>{Services}</td>
<td>{cnum}</td>
<button
onClick={() => this.deleteById(_id)}
disabled={isLoading}
>
Delete
</button>
</tr>
))
: "No Data Found"}
</table>
);
}
}
export default TourPage;
Can you try this ?
render() {
deleteDoc = (id) => {
await fetch('service_url', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: id} )
.then(async response => {
await response.json().then(data => {
console.log(data);
});
})
.catch(err => {
console.log(err)
})
}
return (
<table id="customers">
<tr>
<th>siteLocation</th>
<th>Services</th>
<th>cnum</th>
</tr>
{this.state.myData.length > 0 ? this.state.myData.map((data, index) => (
<tr>
<td>{data.location}</td>
<td>{data.Services}</td>
<td>{data.cnum}</td>
<button onClick={this.deleteDoc(data._id)} disabled={this.state.isLoading}> Delete </button>
</tr>
))
: "No Data Found"}
</table>
);
}

Sort data by title in React

how can i sort my data by title? This is my code:
And how can i call this 3 calls at the same time? I tried with "Promise All" but didn't work for me..
Thanks for help! ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
import './Style.css';
class PostList extends React.Component {
constructor(props) {
super(props);
this.state = {
error: null,
isLoaded: false,
data: [],
items: []
};
}
componentDidMount() {
fetch(this.props.url)
.then(res => res.json())
.then(
(result) => {
this.setState({
isLoaded: true,
data: result.data,
items: result.items
});
},
(error) => {
this.setState({
isLoaded: true,
error
});
}
)
}
render() {
const { error, isLoaded, data } = this.state;
if (error) {
return <div>Error: {error.message}</div>;
} else if (!isLoaded) {
return <div>Please wait...</div>;
} else {
return (
<div> <table style={{ width: '100%'}}>
{data.items.map(item => (
<div>
<tr>
<th>Title:</th> <td>{item.title}</td>
</tr>
<tr>
<th>Artist:</th> <td>{item.artist}</td>
</tr>
<tr>
<th>Label:</th> <td>{item.label}</td>
</tr>
<tr>
<th>Year:</th> <td>{item.year}</td>
</tr>
</div>
))}
</table>
</div>
);
}
}
}
export default PostList
AND
import React, {Component} from 'react';
import PostList from './PostList';
class index extends Component {
render () {
return (
<div style={{
display: 'inline-flex'
}}>
<PostList url={"https://api.netbet.com/development/randomFeed?website=casino&lang=eu&device=desktop&source=list1"} />
<PostList url={"https://api.netbet.com/development/randomFeed?website=casino&lang=eu&device=desktop&source=list2"} />
<PostList url={"https://api.netbet.com/development/randomFeed?website=casino&lang=eu&device=desktop&source=list3"} />
</div>
)
}
}
export default index;
To sort the items just use Array.prototype.sort and String.prototype.localeCompare to compare the titles:
const sortedItems = data.items.sort((item1, item2) => item1.title.localeCompare(item2.title));
// and then render sorted items
{sortedItems.map(item => (...)}
If you want to do three calls at the same time you really need to use Promise.all. It can be done in parent component, or inside of PostList. So you can do the following:
const LIST_URLS = [
'https://api.netbet.com/development/randomFeed?website=casino&lang=eu&device=desktop&source=list1',
'https://api.netbet.com/development/randomFeed?website=casino&lang=eu&device=desktop&source=list2',
'https://api.netbet.com/development/randomFeed?website=casino&lang=eu&device=desktop&source=list3'
];
...
async componentDidMount() {
this.setState({ isLoading: true });
try {
const lists = await Promise.all(LIST_URLS.map((url) => {
return fetch(this.props.url).then(res => res.json());
});
const list = lists.flat();
const sortedList = data.items.sort((item1, item2) => item1.title.localeCompare(item2.title));
this.setState({ list: sortedList });
} catch (error) {
this.setState({ error });
} finally {
this.setState({ isLoading: false });
}
}
render() {
// here you can just render single list with all the items, passing them as a prop
const { isLoading, error, items } = this.state;
return (
<div>
{isLoading && 'Loading...'}
{items && <PostList list={this.state.list} />}
{error && 'Failed to fetch'}
</div>
);
}
If all 3 API data should be sorted, then you have to use like below. If you want individual API responses to be sorted use sort before updating the state.
class PostList extends React.Component {
constructor(props) {
super(props);
this.state = {
error: null,
isLoaded: false,
data: [],
items: [],
};
this.callAPi = this.callAPi.bind(this);
}
callAPi(url) {
return fetch(url)
.then((res) => res.json())
.then(
(result) => {
this.setState({
isLoaded: true,
data: [...result.data].sort((item1, item2) =>
item1.title.localeCompare(item2.title)
),
items: [...result.items].sort((item1, item2) =>
item1.title.localeCompare(item2.title)
),
});
},
(error) => {
this.setState({
isLoaded: true,
error,
});
}
);
}
componentDidMount() {
Promise.all(props.urls.map(this.callAPi));
}
render() {
const { error, isLoaded, data } = this.state;
if (error) {
return <div>Error: {error.message}</div>;
} else if (!isLoaded) {
return <div>Please wait...</div>;
} else {
return (
<div>
<table style={{ width: "100%" }}>
{data.items.map((item) => (
<div>
<tr>
<th>Title:</th> <td>{item.title}</td>
</tr>
<tr>
<th>Artist:</th> <td>{item.artist}</td>
</tr>
<tr>
<th>Label:</th> <td>{item.label}</td>
</tr>
<tr>
<th>Year:</th> <td>{item.year}</td>
</tr>
</div>
))}
</table>
</div>
);
}
}
}
USE
<PostList
urls={[
"https://api.netbet.com/development/randomFeed?website=casino&lang=eu&device=desktop&source=list1",
"https://api.netbet.com/development/randomFeed?website=casino&lang=eu&device=desktop&source=list2",
"https://api.netbet.com/development/randomFeed?website=casino&lang=eu&device=desktop&source=list3",
]}
/>;

using checkboxes to change state and sort list

I have a list like this:
<div className="doubleCol">
{this.state.symptoms.map(item => (
<ListItem key={item.ObjectID}>
<input type="checkbox" className="sympSelect" />
{item.name}
</ListItem>
))}
</div>
All the items rendered have checkbox and I want it to filter a different list elsewhere on the page based on which boxes are checked. To do that I need the checkboxes to change the state and pass the new state to a method which is supposed to filter and display only those items on the second list with id's associated to items on the first list.
From what I have read it shouldn't matter for this purpose if the checkboxes are controlled or uncontrolled.
class Home extends React.Component {
state = {
conditions: [],
symptoms: [],
selectedSymptom: []
}
componentDidMount() {
this.getConditionsMethod();
this.getSymptomsMethod();
}
getConditionsMethod = () => {
API.getConditions()
.then(data => {
console.log(data);
data.data.sort((a, b) => a.name.localeCompare(b.name))
this.setState({
conditions: data.data
})
})
.catch(err => console.log(err))
};
filterConditionsMethod = () => {
API.getConditions()
.then(data => {
console.log(data);
data.data.sort((a, b) => a.name.localeCompare(b.name));
this.setState({
selectedSymptom: data.data
})
})
.catch(err => console.log(err))
};
But I am kind of stuck on how to structure the onChange for when the box is checked and how to make that implement the filter.
Here is you solution you can add onChange event for checkbox and filter your records as selectedSymptoms and symptoms. Please check code is
import React, { Component } from "react";
class Home extends Component {
constructor(props) {
super(props);
this.state = {
conditions: [],
symptoms: [
{ ObjectID: 1, name: "xyz" },
{ ObjectID: 2, name: "pqr" }
],
selectedSymptom: [],
checked: ""
};
}
updateCheckBox = (event, item) => {
if (event.target.checked) {
let selectedList = this.state.selectedSymptom;
selectedList.push(item);
this.setState({
...this.state,
checked: this.state.checked == "checked" ? "" : "checked",
selectedSymptom: selectedList
});
} else {
const symptomss = this.state.selectedSymptom.filter(element => {
if (element.ObjectID != data.ObjectID) {
return item;
}
});
this.setState({
...this.state,
checked: "",
selectedSymptom: symptomss
});
}
};
render() {
return (
<div className="doubleCol">
{this.state.symptoms.map(item => (
<ListItem key={item.ObjectID}>
<input
type="checkbox"
className="sympSelect"
onChange={this.updateCheckBox(e, item)}
id="symptoms_id"
defaultChecked={this.state.checked}
/>
{item.name}
</ListItem>
))}
</div>
);
}
}
export default Home;

I am trying to display specific data by passing a parameter to a fetch call

I have a component that is a select box, i added an onChange to the select box to "capture" its data and set it to a variable in state. I then try to pass it as props to another component [i.e the "display component"] then i use this.props at the end of a new fetch call in the display component to display the data.........it doesn't work. Please Help.
class Test extends Component {
constructor(props) {
super(props)
this.state = {
routes: [],
vessel: ''
}
this.makeChange = this.makeChange.bind(this)
}
componentDidMount() {
fetch(`http://localhost:5000/routes`)
.then(res => res.json())
.then(data => this.setState({
routes: data
}))
}
makeChange(event) {
this.setState({
vessel: event.target.value
})
}
render() {
let { routes } = this.state
return (
<>
<select onChange={this.makeChange}>
<option>Select A Vessel</option>
{routes.map(vessel => {
return (
<option key={uuidv4()}>{vessel.vessel}</option>
)
})}
</select>
<VRoute vessel={this.state.vessel} />
</>
)
}
}
}
-----------------------DISPLAY COMPONENT BELOW-------------------------------
class VRoute extends Component {
constructor(props) {
super(props)
this.state = {
routes: [],
}
}
componentDidMount() {
fetch(`http://localhost:5000/routes/${this.props.vessel}`)
.then(res => res.json())
.then(data => this.setState({
routes: data
}))
}
render() {
let { routes } = this.state;
return ( <table>
<tbody>
</tr>
{routes.map(value => {
return (
<tr key={uuidv4()}>
<td>{value.departure_port}</td>
<td>{value.arrival_port}</td>
<td>{value.departure_time}</td>
<td>{value.arrival_time}</td>
<td>{value.date_stamp}</td>
<td>{value.price}</td>
<td><button className='delete-btn'>x</button></td>
</tr>
)
})}
</tbody>
Try this:
<select onChange={this.makeChange}>
<option>Select A Vessel</option>
{routes.map(vessel => {
return (
<option key={uuidv4()} value={vessel.vessel}>{vessel.vessel}</option>
)
})}
</select>
<VRoute vessel={this.state.vessel} />
</>
Display component..
componentWillUpdate(nextProps) {
if (nextProps.vessel !== this.state.vessel) {
this.setState({vessel: nextProps.vessel}, () => {
fetch(`http://localhost:5000/routes/${this.state.vessel}`)
.then(res => res.json())
.then(data => this.setState({
routes: data
}))
})
}
}

Material UI Switch does not update immediately in React

I have a row component that contains all information about a project and a switch that shows the active status of the project (T or F).
render() {
const dateDisplay = moment(this.props.createdAt).format('MMM YYYY');
return (
<tr
className="experiment-list__row"
onMouseOver={() => this.props.onRowHovered(this.props.rowItems.id)}
>
<td>{this.props.rowItems.name}</td>
<td>{this.props.rowItems.owner}</td>
<td>{dateDisplay}</td>
<td className="experiment-list--col__switch">
<Switch
color="primary"
checked={this.props.rowItems.status}
onChange={()=>{this.handleSubmit(this.props.rowItems.id, this.props.rowItems.status)}}
/>
</td>
</tr>
);
}
It looks like this. When I click the switch it is supposed to toggle and change the status based on the current status. The handleSubmit does it for me.
handleSubmit(rowID: any, rowStatus: any) {
console.log(rowID, rowStatus)
makeMutation(UpdateExperimentQuery, {
update: {
id: rowID,
data: {
status: !rowStatus
},
},
})
.then(responseData => {
console.log(responseData)
})
.catch(err => {
console.log(err);
});
}
It updates the data correctly.
However, it does not get updated immediately even though the checked attribute of the switch represents the status of the row.
When I refresh it, it changes, but I want it to show it immediately since that's the point of using react.
Please help
EDIT
Displays the Info
<div className="experiments-list-container">
<List
onRowHovered={this.getExperimentID}
rowItems={this.state.experimentData}
/>
</div>
This is a different Component ListRow
const List = props => {
return (
<table className="experiment-list">
<tbody>
<ListHeader />
{props.rowItems.map((data, i) => (
<ListRow key={i} rowItems={data} onRowHovered={props.onRowHovered} />
))}
</tbody>
</table>
);
};
The render of ListRow
export class ListRow extends Component<ListRowProps, ListRowState> {
constructor(props) {
super(props);
this.state = {
experimentData: [],
status: props.status //unused right now
};
this.handleSubmit = this.handleSubmit.bind(this);
}
// also not used now
componentWillUpdate() {
if (this.state.status !== this.props.status) {
this.setState({
status: this.props.status,
});
}
}
handleSubmit(rowID: any, rowStatus: any) {
console.log(rowID, rowStatus)
makeMutation(UpdateExperimentQuery, {
update: {
id: rowID,
data: {
status: !rowStatus
},
},
})
.then(responseData => {
console.log(responseData)
})
.catch(err => {
console.log(err);
});
}
render() {
const dateDisplay = moment(this.props.createdAt).format('MMM YYYY');
return (
<tr
className="experiment-list__row"
onMouseOver={() => this.props.onRowHovered(this.props.rowItems.id)}
>
<td>{this.props.rowItems.name}</td>
<td>{this.props.rowItems.owner}</td>
<td>{dateDisplay}</td>
<td className="experiment-list--col__switch">
<Switch
color="primary"
checked={this.props.rowItems.status}
onChange={()=>{this.handleSubmit(this.props.rowItems.id, this.props.rowItems.status)}}
/>
</td>
</tr>
);
}
}
EDIT
changeStatus(rowID, rowStatus) {
// close if the selected employee is clicked
console.log(rowID, rowStatus)
makeMutation(UpdateExperimentQuery, {
update: {
id: rowID,
data: {
status: !rowStatus
},
},
})
.then(responseData => {
setTimeout(() => {
this.componentWillMount();
},1000);
console.log('responseData', responseData)
})
.catch(err => {
console.log(err);
});
}
this updates the data and gets called in the List component.
componentWillMount() {
let filteredData = []
//this.props.fetchExperiments();
makeQuery(ExperimentsListQuery)
.then(responseData => {
this.setState(prevState => ({
experimentData: responseData.Experiments,
}));
for(var i = 0; i < this.state.experimentData.length; i++) {
console.log(this.state.experimentData[i])
if(this.state.experimentData[i].status === this.state.viewActive) {
filteredData.push(this.state.experimentData[i])
}
}
this.setState({
filteredExpData: filteredData
})
})
.catch(err => {
//actions.setSubmitting(false);
console.log(err);
});
}
this fetches/filters the data

Categories