How to implement DELETE method in axios and React? - javascript

I cannot implement delete button.
I have api endpoint 'DELETE /.../{id}'.
Have ApiService.js:
deleteById(id) {
return axios.delete(`${ACCOUNT_API_BASE_URL}/${id}`)
}
and here is my class:
class Account extends Component {
constructor(props) {
super(props);
this.state = {
item: {
id: props.match.params.id,
name: '',
email: '',
password: '',
link: ''
}
};
this.deleteById = this.deleteById.bind(this);
}
componentDidMount() {
// eslint-disable-next-line
if (this.state.item.id === -1) {
return -1
}
ApiService.fetchAccountById(this.state.item.id)
.then(response => this.setState({
item: {
name: response.data.name,
email: response.data.email,
password: response.data.password,
link: response.data.link
}
}))
}
deleteById(id) {
ApiService.deleteById(id)
.then(res => console.log(res.data))
}
render() {
return (
<div>
<h3>{this.state.item.name}</h3>
<ul>
{this.state.item.id}
<li className={c.itemEmail}>Email: {this.state.item.email}</li>
<li>Password: {this.state.item.password}</li>
<li>Link: {this.state.item.link}</li>
</ul>
<button onClick={this.deleteById(this.state.item.id)}>Delete</button>
</div>
)
}
}
It deletes data after requesting page(get method), but not by clicking delete button.
If I set this.deleteById to <button onClick= to , I receive:
'DELETE http://localhost:8080/api/.../undefined 400'

First, you are removing the id property from you item in componentDidMount:
ApiService.fetchAccountById(this.state.item.id)
.then(response => this.setState({
item: { // now item doesn't have id anymore
name: response.data.name,
email: response.data.email,
password: response.data.password,
link: response.data.link
}
}))
So keep your id like this:
ApiService.fetchAccountById(this.state.item.id)
.then(response => this.setState({
item: {
id: this.state.item.id,
name: response.data.name,
email: response.data.email,
password: response.data.password,
link: response.data.link
}
}))
Second, you are executing the function instead of passing the function to onClick, change your onClick value to:
onClick={() => {this.deleteById(this.state.item.id)}}

<button onClick={() => this.deleteById(this.state.item.id)}>Delete</button>

Related

Updating redux state by a local state of checkbox items

there are similiar questions in stackoverflow but I I did not find what I was looking for.
I have a donorDonationForm which is a class componenet that connected to the redux state. The porpuse of that componenet is to collect inormation about a person that want to donate electronics items. At this point, I want to save those items in an array (maybe with an object in the future).
my redux state save the donor info and the reducer looks like this:
import {CHANGE_INPUT_FIELD} from '../utils/constants';
const initialStateInputs = {
// update the state
donorFields: {
name: '',
phone: '',
area: '',
yeshuv: '',
address: ''
// dateOfOffer: ''
},
donationFields: {
// donorID: '',
// vulonteerID: '',
type: [],
quantity: 1,
status: 'NOT_HANDLED',
comments: ''
// lastDateHandled: ''
}
// }, items: [ //need to add quantity
// {id: 1, name: "LAPTOP", isChecked: false, label: 'מחשב'},
// {id: 2, name: "HEADPHONES", isChecked: false, label: 'אוזניות'},
// {id: 3, name: "OTHER", isChecked: false, label: 'אחר'},
// ]
}
export const donorDonationInputsReducer = ( state = initialStateInputs, action={} ) => {
switch(action.type) {
case CHANGE_INPUT_FIELD:
return Object.assign( {}, state,
{
donorFields : {...state.donorFields,...action.payload},
donationFields: {...state.donationFields,...action.payload},
// items : {...state.items,...action.payload},
// isChecked: action.payload
})
default:
return state;
}
}
As you can see the items is commented by now, and I am managing the state of the item in a local state, and that how the comp looks like:
import React, {Component} from 'react';
import { connect } from 'react-redux';
import { setInputField } from '../actions/formAction';
import CheckBox from '../components/CheckBox/CheckBox';
import FormInput from '../components/FormInput/FormInput';
import {selectAreasOptions_2} from '../utils/constants';
import "./form.css";
const mapStateToProps = (state) => {
return {
donorFields: state.donorDonationInputsReducer.donorFields,
donationFields: state.donorDonationInputsReducer.donationFields
}
}
const mapDispatchToProps = dispatch => {
return {
onInputChange: event => {
const {name, value} = event.target;
dispatch(setInputField( { [name]:value} ) )
}
}
}
class donorDonationForm extends Component {
constructor() {
super();
this.state = {
items: [
{id: 1, name: "LAPTOP", isChecked: false, label: 'מחשב'},
{id: 2, name: "HEADPHONES", isChecked: false, label: 'אוזניות'},
{id: 3, name: "OTHER", isChecked: false, label: 'אחר'},
]
,
type: []
}
}
handleCheckChieldElement = (event) => {
let {items, type} = this.state;
let arr = [];
items.forEach(item => {
if (item.name === event.target.value) {
item.isChecked = event.target.checked;
// console.log(`item.name :${item.name }`);
// console.log(`event.target.value :${event.target.value}`);
// console.log(`event.target.checked :${event.target.checked}`);
}
})
items.map(item => item.isChecked ? arr.push(item.name) : null)
this.setState({items: [...items], type: [...arr]});
}
onButtonSubmit = (event) => {
console.log(this.props.donorFields);
event.preventDefault();
fetch('http://localhost:8000/api/donor', {
method: 'post',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
...this.props.donorFields
})
})
.then(response => response.json())
.then(resp => console.log(resp))
.catch( err => console.log(err) )
}
// componentDidUpdate(prevProps, prevState) {
// const {items, type} = this.state;
// // const type = [];
// if (prevState.items !== items) {
// console.log('items state has changed');
// items.map (item => item.isChecked ?
// this.setState({type: [...type,item.name]}) : null)
// // if (item.isChecked) { type.push(item.name) } ;
// console.log(type);
// }
// }
render() {
console.log(this.state.items);
console.log(this.state.type);
const { onInputChange } = this.props;
return (
<div>
<h1 className="pt4"> פרטי תורם</h1>
<form className=" black-80 pt2" >
<section className=" grid-container">
<FormInput
id="name"
name="name"
type="text"
onInputChange={onInputChange}
label="שם "
required
/>
<FormInput
id="phone"
name="phone"
type="tel"
onInputChange={onInputChange}
label="מספר טלפון "
required
/>
<FormInput
id="address"
name="address"
type="text"
onInputChange={onInputChange}
label="כתובת "
required
/>
<FormInput
id="yeshuv"
name="yeshuv"
type="text"
onInputChange={onInputChange}
label="עיר "
required
/>
<FormInput
id="comments"
name="comments"
onInputChange={onInputChange}
label="הערות "
required
/>
<FormInput
id="area"
name="area"
onInputChange={onInputChange}
label="איזור "
select={selectAreasOptions_2}
/>
{/* type */}
<div className="measure-narrow">
<label htmlFor="type" className="f5 b db mb2">מעוניין לתרום
<span className="normal black-60"> *</span>
</label>
{
this.state.items.map( (item, i) => {
return (
<CheckBox
key={i}
onChange={this.handleCheckChieldElement}
checked={ item.isChecked }
value= {item.name}
label = {item.label}
/>
);
})
}
</div>
</section>
<input type="submit" value="שלח"
className="b bg-light-blue pa2 hover pointer"
onClick={this.onButtonSubmit}
/>
</form>
</div>
);
}
}
export default connect(mapStateToProps, mapDispatchToProps)(donorDonationForm);
My main goal is that the type array - the final donation, will update the redux state before submitting this form. I tried with componentDidUpdate but didn't make it. What is the best way for tracking the checked items, updating the array and then update the type array which is the final donation in the redux state? should I do that in the onButtonSubmit method - before sending the data to the server (and thats way saving the looping over the items array for searching the checked elements) ?
Better approach would be do inside onButtonSubmit
Let me briefly explain the tasks:
inputChangeHandler to update this.state.items
Go with the final this.state.items value Array of items inside onButtonSubmit
After getting API response update the application level Redux state with Array of items.
Note: Dispatch the action. Reducer will update the Redux state. Following code will do this:
// Action
export const setItems = (data) => (dispatch) => {
dispatch({type: 'SET_ITEMS', payload: data})
}
// mapDispatchToProps
const mapDispatchToProps = (dispatch) =>
bindActionCreators(
{
setItems,
...others
},
dispatch
)
// onSubmitButton
onButtonSubmit = (event) => {
console.log(this.props.donorFields);
event.preventDefault();
fetch('http://localhost:8000/api/donor', {
method: 'post',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
...this.props.donorFields
})
})
.then(response => this.props.setItems(response.json())) // will update the state.
.then(resp => console.log(resp))
.catch( err => console.log(err) )
}
// Reducer
export const donorDonationInputsReducer = ( state = initialStateInputs, action={} ) => {
switch(action.type) {
case CHANGE_INPUT_FIELD:
return Object.assign( {}, state,
{
donorFields : {...state.donorFields,...action.payload},
donationFields: {...state.donationFields,...action.payload},
// items : {...state.items,...action.payload},
// isChecked: action.payload
})
case SET_ITEMS:
return {
...state,
items: action.payload
}
default:
return state;
}
}
That's it.
Happy Coding :)

JS Validation input

I'm just starting my adventure in react.
I just want to do the number validation.
I found many solutions but none work. from here I took the solution Only numbers. Input number in React
I don't know further this is happening
this is the code with the added solution I found.
import React, { Component } from 'react';
import validator from 'validator';
export default class GetApp extends Component {
state = {
// creditId: '',
err: false,
name: '',
firstName: '',
lastName: '',
pesel: '',
productName: '',
value: ''
}
constructor(props) {
super(props);
this.state = {
creditId: ''
}
}
onChange = (e) => {
//this.setState({ creditId: e.target.value });
}
handleChange(evt) {
const creditId = (evt.target.validity.valid) ? evt.target.value : this.state.creditId;
this.setState({ creditId });
}
handleSubmit = event => {
event.preventDefault();
fetch(`http://localhost:8200/credit/getCredit/${this.state.creditId}`)
.then(res => {
if (res.ok) {
return res
}
}).then(res => res.json())
.then(data => {
this.setState({
err: false,
name: data.credit.name,
firstName: data.customer.firstName,
lastName: data.customer.lastName,
pesel: data.customer.pesel,
productName: data.product.productName,
value: data.product.value
})
})
.catch(err => {
console.log(err);
this.setState({
err: true
})
})
}
render() {
let content = null;
if (!this.state.err && this.state.creditId) {
content = (
<div>
<p>Name: {this.state.name}</p>
<p>First Name: {this.state.firstName}</p>
<p>Last Name: {this.state.lastName}</p>
<p>PESEL: {this.state.pesel}</p>
<p>Product Name: {this.state.productName}</p>
<p>Value: {this.state.value}</p>
</div>
)
}
return (
<form onSubmit={this.handleSubmit}>
<div className="container">
<h2>Get Credit</h2>
<label>Credit Number:</label>
<input type='text' name="creditId" value={this.state.creditId} pattern="[0-9]*" onInput={this.handleChange.bind(this)} />
<div>
<button type="submit">Submit</button>
<p>{this.state.err ? `Dont search: ${this.state.creditId}` : content}</p>
<div>
</div>
</div>
</div>
</form>
)
}
}
Thanks for help
You could also change the input type to number https://www.w3schools.com/tags/att_input_type_number.asp . This won't allow users to set anything else but numeric (0-9) characters and is a bit more strict.

React setState wont re-render

I'm working on a self project React for front-end and node for back-end, part of the app is that when a user submits an image url it counts the entries and it updates in the server then it should re-render on the front-end to the screen. The problem is it doesn't re-render, i have console.log tested and everything works from the server side, the problem is in the setState in react wont re-render and i'm hoping any one help me understand why it is not working?
Here is the code related to my problem
class App extends Component {
constructor() {
super()
this.state = {
input: '',
imgUrl: '',
box: {},
route: 'signin',
isSignedIn: false,
user: {
id: '',
name: '',
email: '',
entries: 0,
joined: '',
},
}
}
loadUser = data => {
this.setState({
user: {
id: data.id,
name: data.name,
email: data.email,
entries: data.entries,
joined: data.joined,
},
})
}
onButtonSubmit = () => {
fetch('http://localhost:3001/image', {
method: 'put',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
id: this.state.user.id,
}),
})
.then(response => response.json)
.then(count => {
this.setState({ ...this.state.user, entries: count })
})
.catch(err => console.log(err))
}
}
render() {
return (
<div className="App">
<Navigation
isSignedIn={this.state.isSignedIn}
onRouteChange={this.onRouteChange}
/>
{this.state.route === 'home' ? (
<div>
<Rank
name={this.state.user.name}
entries={this.state.user.entries}
/>
<ImageLinkForm
onInputChange={this.onInputChange}
onButtonSubmit={this.onButtonSubmit}
/>
<FaceRecognition box={this.state.box} imgUrl={this.state.imgUrl} />
</div>
) : this.state.route === 'signin' ? (
<Signin loadUser={this.loadUser} onRouteChange={this.onRouteChange} />
) : (
<Register
loadUser={this.loadUser}
onRouteChange={this.onRouteChange}
/>
)}
</div>
)
}
this code is suppose to print the entries count on the screen but its not
this.setState({...this.state.user, entries: count})
here is the server side where entries gets updated and sent to the front-end
app.put('/image', (req, res) => {
const { id } = req.body
let found = false
database.users.forEach(user => {
if (user.id === id) {
found = true
user.entries++
return res.json(user.entries)
}
})
if (!found) {
res.status(400).json('not found')
}
})
here is the rank Component where entries gets printed
import React from 'react';
const Rank = ({ name, entries}) => {
return (
<div>
<div className='rank'>
{`${name} your current rank is...`}
</div>
<div className='white f1 '>
{entries}
</div>
</div>
);
}
export default Rank;
Thanks in advance.
I don’t see any use of doing ...this.state.user in setState So
Change
this.setState({...this.state.user, entries: count})
To
this.setState({entries: count})

Reactjs: how to update vote counts in reactjs

The code below was designed to update a voting system. It works fine by displaying the results as the page loads.
Here is my problem: I need to update each user's vote any time the Get Vote Count button is clicked.
In the backend, I have php code which returns the array data as per below.
Can someone help me with displaying the array values and updating eg (vote to 11) depending on how the user voted?
<?php
// Update user response on a post
$return_arr[]= array("vote"=>"11");
echo json_encode($return_arr);
exit;
?>
Here is the array return by axios API Call
[{"vote":"11"}]
Here is the code
import React, { Component, Fragment } from "react";
import { render } from "react-dom";
import axios from 'axios';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
loading: false
};
}
componentDidMount() {
this.setState({
data: [
{ id: "1", name: "Tony", vote: "3" },
{ id: "2", name: "Mark", vote: "6" },
{ id: "3", name: "Joy", vote: "2" }
]
});
}
handleVote(person_id, person_vote) {
const data_vote = {
person_id: person_id,
person_vote: person_vote
};
axios
.get("http://localhost/vote.php", { data_vote })
.then(response => {
this.setState({ result_vote: response.data });
console.log(this.state.result_vote);
})
.catch(error => {
console.log(error);
});
}
render() {
return (
<span>
<label>
<ul>
{this.state.data.map((person, i) => (
<li key={i}>
{person.name} --(vote count: {person.vote})
<br />
<input
type="button"
value="Get Vote Counts"
onClick={() => this.handleVote(person.id, person.vote)}
/>
</li>
))}
</ul>
</label>
</span>
);
}
}
You should set your data state after getting the vote data from the fetch response. You have person_id in your handler and getting an array including vote value. So, map through your data state find the relevant person and update its vote value.
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
loading: false
};
}
componentDidMount() {
this.setState({
data: [
{ id: "1", name: "Tony", vote: "3" },
{ id: "2", name: "Mark", vote: "6" },
{ id: "3", name: "Joy", vote: "2" }
]
});
}
handleVote(person_id, person_vote) {
const data_vote = {
person_id: person_id,
person_vote: person_vote
};
axios
.get("http://localhost/vote.php", { data_vote })
.then(response => {
const newData = this.state.data.map(person => {
if (person.id !== person_id) return person;
return { ...person, vote: response.data[0].vote };
});
this.setState(state => ({
data: newData
}));
})
.catch(error => {
console.log(error);
});
}
render() {
return (
<span>
<label>
<ul>
{this.state.data.map(person => (
<li key={person.id}>
{person.name} --(vote count: {person.vote})
<br />
<input
type="button"
value="Get Vote Counts"
onClick={() => this.handleVote(person.id, person.vote)}
/>
</li>
))}
</ul>
</label>
</span>
);
}
}
Try to avoid using an index as a key. You have a person.id so use it in your map method. Also, as an enhancement, you can refactor your code and create a Person component. You can pass the related data and vote handler then setup the update logic there.
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
loading: false,
};
}
componentDidMount() {
this.setState({
data: [
{ id: "1", name: "Tony", vote: "3" },
{ id: "2", name: "Mark", vote: "6" },
{ id: "3", name: "Joy", vote: "2" },
],
});
}
handleVote = (person) => {
const data_vote = {
person_id: person.id,
person_vote: person.vote,
};
axios
.get("http://localhost/vote.php", { data_vote })
.then((response) => {
const newData = this.state.data.map((el) => {
if (el.id !== person.id) return el;
return { ...el, vote: response.data[0].vote };
});
this.setState({ data: newData });
})
.catch((error) => {
console.log(error);
});
};
render() {
return (
<span>
<label>
<ul>
{this.state.data.map(person => (
<Person
key={person.id}
person={person}
handleVote={this.handleVote}
/>
))}
</ul>
</label>
</span>
);
}
}
const Person = (props) => {
const { person, handleVote } = props;
const onVote = () => handleVote(person);
return (
<li>
{person.name} --(vote count: {person.vote})
<br />
<input type="button" value="Get Vote Counts" onClick={onVote} />
</li>
);
};
So, since your handler function is getting the person_id and your call is returning the new vote count, you should update the current person object in your data table in state.
Here is an example:
Updating the vote count for the current user

Count occurrences results from API JSON response in React.js

Based on this previous questions I made (Show fetch results in render return() in React.js), from which I received json results, I now need to count the number of sofas that each brand has. For example, Brand X has 2 occurences and Brand Y has 3043.
I get the brand from one sofa by calling myUrlApi + /couch-model on fetch and the json is something like what you can see in the picture below.
Has you can see each sofa has associated to itself a brand. What I want to count is how many sofa each brand has.
I'll put my current code here:
export class Main extends React.Component {
constructor(props) {
super(props);
this.state = {
token: {},
isLoaded: false,
models: []
};
}
componentDidMount() {
/*code to generate token, not needed for the purpose of the question*/
fetch(url + "/couch-model/?limit=9", {
method: "GET",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
Authorization: "JWT " + JSON.parse(localStorage.getItem("token")).token
}
})
.then(res => {
if (res.ok) {
return res.json();
} else {
throw Error(res.statusText);
}
})
.then(json => {
this.setState(
{
models: json.results
},
() => {}
);
});
}
render() {
const { isLoaded, models } = this.state;
if (!isLoaded) {
return <div>Loading...</div>;
} else {
return (
<div>
{models.map(model => (
<a href="/sofa" key={model.id}>
<div className="Parcelas">
<img src={img_src} className="ParcImage" alt="sofa" />
<h1>Sofá {model.name}</h1>
<h2>
1,200<span>€</span>
</h2>
<p
className="Features"
dangerouslySetInnerHTML={{ __html: model.description }}
/>
<button className="Botao">
<p className="MostraDepois">Ver Detalhes</p>
<span>+</span>
</button>
<img
src="../../img/points.svg"
className="Decoration"
alt="points"
/>
</div>
</a>
))}
</div>
);
}
}
}
Hope I was clear, ask if you have any doubt.
if your results look like this as you said in your post :
{
results: [
{
brand: { name: "Brand-A", image: "", etc: "..." },
category: "A",
code: "AAA",
name: "SofaA",
price: 1200
},
{
brand: { name: "Brand-A", image: "", etc: "..." },
category: "A",
code: "AAA",
name: "SofaB",
price: 1200
},
{
brand: { name: "Brand-B", image: "", etc: "..." },
category: "A",
code: "AAA",
name: "SofaC",
price: 1200
}
]
}
You can add a state property like sofasPerBrand initialized to {}
constructor(props) {
super(props);
this.state = {
token: {},
isLoaded: true,
models: [],
sofasPerBrand: {}
};
}
And add in the setState function in componentDidMount the RIYAJ KHAN reduce function like this :
this.setState(
{
models: json.results,
sofasPerBrand: json.results.reduce((coundData, sofa, index) => {
if (!!coundData[sofa.brand.name]) {
coundData[sofa.brand.name] += 1;
} else {
coundData[sofa.brand.name] = 1;
}
return coundData;
}, {})
},
() => { }
);
then you can declare it in your render function :
const { isLoaded, models, sofasPerBrand } = this.state;
and use it like that any where :
<ul>
{Object.keys(sofasPerBrand).map(brand=>(
<li>{brand} : {sofasPerBrand[brand]}</li>
))}
</ul>
One can use javascript#reducers for it.
models.reduce((coundData,sofa,index)=>{
if(!!coundData[sofa.brand.name]){
coundData[sofa.brand.name] +=1;
}else{
coundData[sofa.brand.name]=1;
}
return coundData;
}, {})

Categories

Resources