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",
]}
/>;
Related
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?
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>
);
}
Loading in an API and I'm getting .map isn't a function. Been looking through every example and followed them exactly but still getting this error. The error is of course happening at the .map in the ul tag
class Login extends Component {
constructor(props) {
super(props);
this.state = {
items: [],
isLoaded: false
};
}
componentDidMount() {
fetch(
"https://opentdb.com/api.php?amount=10&category=18&difficulty=easy&type=boolean"
)
.then(res => res.json())
.then(json => {
this.setState({ isLoaded: true, items: json });
});
}
render() {
var { isLoaded, items } = this.state;
if (!isLoaded) {
return <div>Loading...</div>;
} else {
return (
<div className="App">
<ul>
{items.map(item => (
<li key={item.results.question}>{item.results.question}</li>
))}
</ul>
</div>
);
}
}
}
export default Login;
Your actual data is coming in json.results, so you need to set json.results in state like,
this.setState({ isLoaded: true, items: json.results });
You need to iterate array like,
{ items.map(item => (
<li key={item.question}>{item.question}</li>
))}
Demo
Im using fetch to post data to my local api, but when trying to get them and error like this occures. In fetch i get result perfectly fine, but after that trying to pass that into state like below:
this.setState({
items: result.items })
but items returns undefined and don't know why ?
My code:
class App extends Component {
constructor(props) {
super(props);
this.state = {
items: [],
error: null,
isLoaded: false
};
this.setState = this.setState.bind(this);
}
componentDidMount() {
fetch("http://localhost:3000/items")
.then(res => res.json())
.then(result => {
console.log(result);
this.setState({
items: result.items,
isLoaded: true
});
console.log(this.state.items)
},
(error) => {
this.setState({
isLoaded: true,
error
});
}
)
}
render() {
const { error, isLoaded, items } = this.state;
if (error) {
return <div>Error: {error.message}</div>;
} else if (!isLoaded) {
return <div>Loading...</div>;
} else {
return (
<ul>
<h1>Saved items:</h1>
{
items && items.map(item => (
<li key={item.name}>
item: {item.name} {item.price}
</li>
))
}
</ul>
);
}
}
}
You can do either:
this.setState({
items: result.items || [],
isLoaded: true
});
or
{
items && items.map(item => (
<li key={item.name}>
{item.name} {item.price}
</li>
))
}
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