How to edit data in store through a component? REACT JS - reactjs

I have logged: false in my store and I need to change it to true on a button action in a component in react js. If you could tell me how to edit/update data in store or share a link?

How to create Store
const redux = require('redux');
const createStore = redux.createStore;
const initialState = {
counter: 0
}
const rootReducer = (state = initialState, action) => {
if(action.type === 'INC_COUNTER'){
return {
...state,
counter: state.counter + 1
};
}
return state;
};
How to call Action
const mapDispatchToProps = dispatch => {
return {
onIncrementCounter: () => dispatch({type:'INC_COUNTER'})
};
};
Calling it on click
<button clicked={this.props.onIncrementCounter} />

Here is a simple React Component which implements create,read,update,delete functionality:
[You can also view code implementation on codesanbox.io https://codesandbox.io/s/81r0n6l112
import React from "react";
import idGenerator from "react-id-generator";
export default class App extends React.Component {
state = {
employees: [],
firstname: "",
lastname: "",
id: 0,
create: true
};
componentDidMount() {
//Intializing sample data
const emps = [
{ firstname: "John", lastname: "Doe", id: 0 },
{ firstname: "Bruno", lastname: "Mars", id: 0 }
];
this.setState({
employees: emps.map(e => {
return {
firstname: e.firstname,
lastname: e.lastname,
id: idGenerator()
};
})
});
}
handleChange = e => {
const name = e.target.name;
this.setState({ [name]: e.target.value });
};
handleCreateEmployee = () => {
if (this.state.employees) {
this.setState({
employees: [
...this.state.employees,
{
firstname: this.state.firstname,
lastname: this.state.lastname,
id: idGenerator()
}
]
});
} else {
this.setState({
employees: [
{
firstname: this.state.firstname,
lastname: this.state.lastname,
id: idGenerator()
}
]
});
}
this.setState({ firstname: "", lastname: "" });
};
handleEdit = e => {
const employee = this.state.employees.find(function(emp) {
if (emp.id === e.target.id) {
return emp;
}
});
this.setState({
firstname: employee.firstname,
lastname: employee.lastname,
id: employee.id,
create: false
});
};
handleDelete = e => {
this.setState({
employees: this.state.employees.filter(function(emp) {
if (emp.id !== e.target.id) return emp;
})
});
};
handleUpdateEmployee = () => {
const employee = {
firstname: this.state.firstname,
lastname: this.state.lastname,
id: this.state.id
};
const employeesupdated = this.state.employees.map(emp => {
if (emp.id === this.state.id) {
return employee;
} else return emp;
});
this.setState((prevStae, props) => ({
employees: employeesupdated,
create: true,
firstname: "",
lastname: ""
}));
};
render() {
const create = this.state.create ? "Save" : "Update";
const { employees } = this.state;
const inputIsEmpty =
this.state.firstname === "" || this.state.lastname === "" ? true : false;
return (
<div>
<input
style={{ width: 120 }}
type="text"
placeholder="Enter Firstname"
onChange={this.handleChange}
name="firstname"
value={this.state.firstname}
/>
<input
style={{ width: 120 }}
type="text"
placeholder="Enter Firstname"
onChange={this.handleChange}
name="lastname"
value={this.state.lastname}
/>
<button
style={{ width: 150 }}
disabled={inputIsEmpty}
onClick={
this.state.create
? this.handleCreateEmployee
: this.handleUpdateEmployee
}
>
{create}
</button>
<br />
<table border="1" style={{ width: 400, paddingTop: 5 }}>
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Edit</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
{employees.map((emp, i) => {
return (
<tr key={i}>
<td>{emp.firstname}</td>
<td>{emp.lastname}</td>
<td>
<button onClick={this.handleEdit} id={emp.id}>
Edit
</button>
</td>
<td>
<button onClick={this.handleDelete} id={emp.id}>
Delete
</button>
</td>
</tr>
);
})}
</tbody>
</table>
</div>
);
}
}
[You can also view the code implementation here][1]
[1]: https://codesandbox.io/s/81r0n6l112

Related

Change the input text file in react

New to React and using a simple table. I'm just testing to change an input text value when I select a button on the same row.
The code below is where I'm stuck. I'm trying to figure out how to change the state value "users" for this row when I click on the button. I'm trying to set the first_name to "Testing".
const [users, setUsers] = React.useState(null);
let usersList =
businessUsersState.data.length > 0 &&
businessUsersState.data.map((item: any, key: number) => {
return (
<tr key={key} data-account={item.account_id}>
<td>
<Form.Control name="first-name" type="input" placeholder="First Name" defaultValue={item.first_name} />
</td>
<td>
<Button variant="primary" type="button" onClick={() => {
debugger;
const row = businessUsersState.data.map((item: any) => ({...item}));
row[key].first_name = 'Testing';
const row1 = usersList[key];
//setUserRow(row);
//setUsers(row);
}}>
</Button>
</td>
</tr>
);
});
setUsers(usersList);
I was reading the following link but I cant seem to get it to work. Any help is appreciated.
Following React docs example of object and array in state
const uniqueId = () => {
// always start with a letter (for DOM friendliness)
let idstr = String.fromCharCode(Math.floor(Math.random() * 25 + 65));
do {
const ascicodeChar = Math.floor(Math.random() * 25 + 65);
idstr += String.fromCharCode(ascicodeChar);
idstr += Math.floor(Math.random() * 99);
} while (idstr.length < 8);
return idstr.toLowerCase();
};
const fakeData = [
{ id: uniqueId(), company: 'abc', contact: 'a#gmail.com', country: 'China' },
{ id: uniqueId(), company: 'def', contact: 'b#gmail.com', country: 'Japan' },
{
id: uniqueId(),
company: 'ghj',
contact: 'c#gmail.com',
country: 'Singapore',
},
{
id: uniqueId(),
company: 'ikl',
contact: 'd#gmail.com',
country: 'Indonesia',
},
{
id: uniqueId(),
company: 'mno',
contact: 'e#gmail.com',
country: 'Thailand',
},
];
export default function App() {
const [data, setData] = React.useState(fakeData);
const handleEdit = (id) => {
setData(
data.map((t) => {
// find item matched given id and mutate that item
if (t.id === id) {
return {
id,
company: `test${id}`,
contact: `test${id}#gmail.com`,
country: `test${id}`,
};
} else {
return t;
}
})
);
};
return (
<div>
<table>
<tr>
<th>Company</th>
<th>Contact</th>
<th>Country</th>
<th>edit</th>
</tr>
{(() => {
if (!data.length) {
return <p>No data available</p>;
}
return data.map((i, index) => {
return (
<tr key={i.id}>
<td>{i.company}</td>
<td>{i.contact}</td>
<td>{i.country}</td>
<td>
{/* pass an id of row to edit fnc */}
<button onClick={() => handleEdit(i.id)}>edit</button>
</td>
</tr>
);
});
})()}
</table>
</div>
);
}
You could try to do the same above example.

How can I disable/gray out dropdown selection checkboxes for two records available in setSubmittedNominees state?

How can I disable/gray out dropdown selection checkboxes for two records available in a state setSubmittedNominees in react hooks ? I tried to pass into submittedNominees into selectedValues and disablePreSelectedValues(true) but it doesn't work that way can someone please advise on this ?
codesandbox link:
https://codesandbox.io/s/magical-haslett-s0oeh?file=/src/App.js
import React, { useRef, useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import { useForm } from "react-hook-form";
import Axios from "axios";
import { Link, useHistory } from "react-router-dom";
import Multiselect from "multiselect-react-dropdown";
const options = [
{ id: 1, name: "Ath", email: "ath.best#test1.com", access: null },
{ id: 2, name: "Arnolds", email: "arnold#test1.com", access: null },
{ id: 3, name: "Alter", email: "alloop#test1.com", access: null },
{ id: 4, name: "Brandan", email: "brandan#test1.com", access: null },
{ id: 5, name: "Ron", email: "ron#test1.com", access: null },
{ id: 6, name: "Rads", email: "rad#test1.com", access: null },
{ id: 7, name: "Sam", email: "sam#y.com", access: null }
];
const submitted = [
{ id: 4, name: "Brandan", email: "brandan#test1.com", access: null },
{ id: 5, name: "Ron", email: "ron#test1.com", access: null }
];
const Selection= () => {
const [option, setOption] = useState([]);
const [selectedOption, setSelectedOption] = useState([]);
const [nomRegister, setNomRegister] = useState([{}]);
const [helperText, setHelperText] = useState("");
const [userEmail, setUserEmail] = useState("");
const [submittedNominees, setSubmittedNominees] = useState([{}]);
const {
register,
handleSubmit,
watch,
formState: { errors },
reset
} = useForm();
const maxOptions = 3;
const history = useHistory();
useEffect(() => {
const userEmail = localStorage.getItem("loginEmail");
setUserEmail(userEmail);
});
useEffect(() => {
const fetchData = async () => {
try {
const res = await Axios.get(
"http://localhost:8000/service/nomineeslist"
);
//const data1 = res.data;
setOption(options);
console.log("Get the list of nominees :" + JSON.stringify(res.data));
} catch (e) {
console.log(e);
}
};
fetchData();
}, []);
useEffect(() => {
const fetchData = async () => {
try {
// const res = await Axios.get(
// "http://localhost:8000/service/submittednominees"
// );
setSubmittedNominees(submitted);
} catch (e) {
console.log(e);
}
};
fetchData();
}, []);
const handleTypeSelect = (e, i) => {
const copy = [...selectedOption];
copy.push(e[i]);
setSelectedOption(copy);
};
const sendNomination = () => {
console.log("What the Array holds: " + JSON.stringify(nomRegister));
const fetchData = async (nomRegister) => {
try {
const res = await Axios.post(
"http://localhost:8000/service/nominateperson",
{ userEmail },
nomRegister
);
if (res.data) {
console.log("Print data:" + res.data);
const successMessage = res.data.message;
setHelperText(successMessage);
setNomRegister(reset);
}
} catch (e) {
console.log(e);
setNomRegister(reset);
setHelperText(e.message);
}
};
fetchData();
};
options.forEach((option) => {
option.displayValue = option.name + "\t" + option.email;
submittedNominees.forEach((item) => {
let subEmail = item.email; // how can I pass those two email to selectedValues and make it disable ?
});
});
const handleChange = (e, i) => {
const { name, email, value } = e.target;
// immutating state (best practice)
const updateList = nomRegister.map((item) => {
return { ...item };
});
const select_Email = selectedOption.map((item) => {
return item.email;
});
//change the specific array case depends on the id //email:emailList[i],
updateList[i] = {
...updateList[i],
name: name,
email: select_Email[i],
reason: value
};
setNomRegister(updateList);
};
return (
<div className="App">
<h1>Nominate a person</h1>
<div className="nomineeSelectBox">
<div id="dialog2" className="triangle_down1" />
<div className="arrowdown">
<Multiselect
onSelect={(e) => handleTypeSelect(e, selectedOption.length)}
options={selectedOption.length + 1 === maxOptions ? [] : options}
displayValue="displayValue"
selectedValues={subEmail}
showCheckbox={true}
emptyRecordMsg={"Maximum nominees selected !"}
/>
</div>
</div>
<div className="nominationcount"></div>
<form onSubmit={handleSubmit(sendNomination)}>
<div className="nomineesSelectedList">
<h4>Selected Nominees</h4>
{selectedOption.map((x, i) => (
<div key={i}>
<div className="row eachrecord">
<div className="column">
<label className="nomlabel">
{x?.name} <b>>></b>
</label>
</div>
<input
required
type="textarea"
placeholder="Please provide reason for nomination.."
key={i}
id={i}
name={x?.name}
className="nomineechoosed"
onChange={(e) => handleChange(e, i)}
/>
</div>
</div>
))}
<div className="row">
<div className="buttongroup">
<input id="Submit" type="submit" value="Submit" />
<input id="Cancel" type="button" value="Cancel" />
</div>
</div>
</div>
</form>
<span className="nominationValidationText">{helperText}</span>
</div>
);
};
export default Selection;
the issue here is that you are showing your dropdown selection checkboxes by displayValue (displayValue="displayValue") and your submitted array that you you will assign to submittedNominees (setSubmittedNominees(submitted)) does not contain displayValue:
const submitted = [
{ id: 4, name: "Brandan", email: "brandan#test1.com", access: null },
{ id: 5, name: "Ron", email: "ron#test1.com", access: null }
];
Solution::
Make your submitted for example like this:
const submitted = [
{
id: 4,
name: "Brandan",
email: "brandan#test1.com",
access: null,
displayValue: "Brandan brandan#test1.com"
},
{
id: 5,
name: "Ron",
email: "ron#test1.com",
access: null,
displayValue: "Ron ron#test1.com"
}
];
Add selectedValues={submittedNominees} to your Multiselect to find out which values you will disable:
<Multiselect
onSelect={(e) => handleTypeSelect(e, selectedOption.length)}
options={selectedOption.length + 1 === maxOptions ? [] : options}
displayValue="displayValue"
disablePreSelectedValues={true}
selectedValues={submittedNominees}
showCheckbox={true}
emptyRecordMsg={"Maximum nominees selected !"}
/>
Codesandbox link

React: loop through array response does not work

I run an axios get request to an Express server to get some dummy data:
customers = [
{ id: 1, firstName: "John" },
{ id: 2, firstName: "Brad" },
{ id: 3, firstName: "Mary" }
];
the data that is returned is determined by a user input: if the user enters "Brad", the result being returned will be { id: 2, firstName: "Brad" }.
For some reason, when I loop through the data returned, nothing works. Looking into the React Chrome Extension, the State returned is as follows:
{
"firstName": "Brad",
"id": 0,
"customers": [],
"res": []
}
Because I am learning React, I will post the whole component for you to see, perhaps the problem is something I don't see yet as a newbie:
class App extends Component {
constructor(props) {
super(props);
this.state = {
firstName: "",
id: 0,
customers: []
};
this.getName = this.getName.bind(this);
}
onChange = e => {
e.preventDefault();
this.setState({ firstName: e.target.value });
};
getName = e => {
e.preventDefault();
axios
.get("/api/customers", {
params: {
firstName: this.state.firstName
}
})
.then(res => {
console.log(res);
this.setState({ res: this.state.customers });
});
};
componentDidMount() {}
render() {
//if (!this.state.customers.length) return "Data not available yet";
return (
<div>
<h2>Customers</h2>
<div className="card card-body mb-4 p-4">
<div className="h1 display-4 text-center">
<h1 className="i fas">Search for a customer</h1>
<p className="lead text-center">Get the Customer's Name Here</p>
<form onSubmit={this.getName}>
<div className="form-group">
<input
type="text"
className="form-control form-control-lg"
placeholder="customer name ..."
name="firstName"
value={this.state.firstName}
onChange={this.onChange}
/>
</div>
<button
className="btn btn-primary btn-lg-block mb-5"
type="submit"
>
Get Customer
</button>
</form>
</div>
</div>
This is where I loop throuhg the data:
{this.state.customers.map(item => (
<li key={item.id}>{item.firstName}</li>
))}
</div>
);
}
}
And here is the Express route I'm calling:
app.get("/api/customers", (req, res) => {
let { firstName } = req.query;
const customers = [
{ id: 1, firstName: "John" },
{ id: 2, firstName: "Brad" },
{ id: 3, firstName: "Mary" }
];
console.log("the customer's name is " + firstName);
var str = customers.filter(x => x.firstName == firstName);
res.json(str);
});
So What I want is to display the data in a element below the input bar.
Try :
this.setState({ customers : res });
instead of :
this.setState({ res: this.state.customers });
Also, try to use React Hooks in order to refactor your code.

Form inputs should clear only with correct submit

My form component looks like :
constructor(props) {
super(props);
this.state = {
startDate: '',
endDate: '',
description: '',
profileId: this.props.profileId
}
this.onStartDateChange = this.onStartDateChange.bind(this);
this.onEndDateChange = this.onEndDateChange.bind(this);
this.onDescriptionChange = this.onDescriptionChange.bind(this);
this.clickHandle = this.clickHandle.bind(this);
}
onStartDateChange(event) {
const startDate = event.target.value
this.setState({
startDate: startDate
})
}
onEndDateChange(event) {
const endDate = event.target.value
this.setState({
endDate: endDate
})
}
onDescriptionChange(event) {
const description = event.target.value
this.setState({
description: description
})
}
clickHandle = () => {
const inputValues = {
startDate: this.state.startDate,
endDate: this.state.endDate,
description: this.state.description
}
this.props.onAddClick(this.state.profileId, inputValues);
}
render() {
return (
<Form>
<div className={"m-3 form-row"}>
<Field type={"date"} className={"form-control col-md-2 mr-2"}
onChange={evt => this.onStartDateChange(evt)}
value={this.state.startDate}
name={"add-start-date"}/>
<Field type={"date"} className={"form-control col-md-2 mr-2"}
onChange={evt => this.onEndDateChange(evt)}
value={this.state.endDate}
name={"add-end-date"}/>
<Field className={"form-control col-md-2 mr-2"}
type={"textarea"}
onChange={evt => this.onDescriptionChange(evt)}
value={this.state.description}
name={"add-description"}/>
<button className="btn btn-info round-btn" href="#"
onClick={this.clickHandle}
type={"button"}><FontAwesomeIcon icon={faPlus}/></button>
</div>
</Form>
}
My action looks like:
export const onAddClick = (profileId, educationData = {
startDate: '',
endDate: '',
description: ''
}) => {
return (dispatch) => {
const education = {
startDate: educationData.startDate,
endDate: educationData.endDate,
description: educationData.description
};
return axios.post(`${ENTRY_API_URL}`)
.then(response => {
dispatch(_addEducation(profileId, response.data))
})
.catch((error) => {
if (error) {
dispatch(_requestFailure(profileId, error.response.data))
}
})
};
};
My store looks like
workExperience: [
{
id: '5d6e3368993694389c903c50',
startDate: '2019-09-04',
endDate: '2019-09-12',
description: 'description'
},
How can I clear input only when request to API is correct and when its wrong leave it. Can I make it without redux-forms ? I tried with some flag in store but it change slowly after I clicked the button. Should I try make some state in redux for this form ?

Build form by using map(), how to put info from this.state?

import React, { Component } from "react";
import myPhone from "../service/checkPhone.js";
import {usersParam} from'../variable.js';
class FormForUserChange extends Component {
constructor() {
super();
this.state = {
name: "",
age: "",
gender: "",
phone: "",
address: "",
display: "none"
};
}
componentWillMount = () => {
this.setState({ name: this.props.userToChange.name });
this.setState({ age: this.props.userToChange.age });
this.setState({ gender: this.props.userToChange.gender });
this.setState({ phone: this.props.userToChange.phone });
this.setState({ address: this.props.userToChange.address });
};
_makeListFormData=(usersParam)=>{
return usersParam.map(each => {
return (
<input
className="form-control"
type="text"
// defaultValue={this.state.{each}}
placeholder={each}
ref={input => (this.each = input)}
/>
);
});
}
_handleChange = event => {
this.setState({ gender: event.target.value });
};
_handleSubmit = event => {
event.preventDefault();
if (
this.name.value &&
this.address.value &&
this.phone.value &&
this.age.value &&
myPhone(this.phone.value)
) {
const changedUser = {
name: this.name.value,
age: this.age.value,
gender: this.state.gender,
phone: this.phone.value,
address: this.address.value,
id: this.props.userToChange.ident
};
this.props.saveChangedUser(changedUser, this.props.userToChange.hash);
} else {
this.setState({ display: "block" });
}
};
render() {
let form;
let btnText;
const styles = {
display: this.state.display
};
const inputsInForm=this._makeListFormData(usersParam);
if (this.props.openModal) {
form = (
<div className="shadow p-3 mb-5 bg-white rounded" id="form">
<form
className="form-control-file. form-container"
onSubmit={this._handleSubmit.bind(this)}
>
{inputsInForm}
<button className="btn btn-primary" type="submit">
Save changes
</button>
</form>
<span id="form-fill-error" style={styles}>
please fill out all fields correct
</span>
</div>
);
} else {
form = "";
}
return (
<div>
<button
className="btn btn-primary"
id="add-user-btn"
disabled="disabled"
>
{btnText}
</button>
{form}
</div>
);
}
}
export default FormForUserChange;
I have an array from which I build inputs for form(_makeListFormData). In phraseholder I have to put info from state(which comes from props).
So in placeholder I should put something like this.state{each} it does't work off course. Can you give me an advise how to make it?
You can use placeholder={this.state[each]} for your situation. Also, use componentDidMount since componentWillMount will be deprecated in the future as #Think-Twice explained. Also, set your state in one time, not separately like that.
const usersParam = ['name', 'age', 'gender', 'phone', 'address'];
class FormForUserChange extends React.Component {
constructor() {
super();
this.state = {
name: "",
age: "",
gender: "",
phone: "",
address: "",
display: "none"
};
}
componentDidMount = () => {
this.setState({
name: this.props.userToChange.name,
age: this.props.userToChange.age,
gender: this.props.userToChange.gender,
phone: this.props.userToChange.phone,
address: this.props.userToChange.address,
});
};
_makeListFormData = (usersParam) => {
return usersParam.map(each => {
return (
<input
className="form-control"
type="text"
// defaultValue={this.state.{each}}
placeholder={this.state[each]}
ref={input => (this.each = input)}
/>
);
});
}
render() {
const inputsInForm = this._makeListFormData(usersParam);
return(
<div>{inputsInForm}</div>
);
}
}
const userToChange = {
name: "foo",
age: 25,
gender: "male",
phone: "123",
address: "some add",
}
ReactDOM.render(<FormForUserChange userToChange={userToChange} />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
This is not solution for your issue though but few issues I would like to address.
Stop using componentWillMount because this is deprecated.
so you can directly assign props in constructor
constructor(props) {
super(props);
this.state = {
name: this.props.userToChange.name,
age: this.props.userToChange.age,
gender: this.props.userToChange.gender,
phone: this.props.userToChange..phone,
address: this.props.userToChange.address,
display: "none"
};
}
Note: you no need to use setState for each. You can do everything thing in single setState like below
this.setState({
name: this.props.userToChange.name,
age: this.props.userToChange.age,
gender: this.props.userToChange.gender,
phone: this.props.userToChange..phone,
address: this.props.userToChange.address,
display: "none"
});

Resources