I use - React Redux and Redux form
I have a user list form which has table of contents with
edit/delete buttons on the right side of each row. When I click
on edit button it should pass the current row values to the user main form.
At the bottom of the form I have a addnew button which redirects to user main form.
My requirement is when I click addnew it should open user main form with empty fields,
when I click edit button on the table row it should open user main form with pre-populated fields with the
current selected row values.
How can I achieve this. Please help. Thanks in advance.
For Ex:
My UserList.js form
renderUsers() {
return this.props.users.reverse().map(user => {
return (
<tbody key={user._id}>
<tr key={user._id}>
<td>{user.email}</td>
<td>{user.firstname}</td>
<td><Link id={user._id} to="#" onClick={() => this.onDeleteUser(user._id)}>
<i className="material-icons">delete</i></Link>
<Link id={user._id} to="user/new"
onClick={ () => here I have to call usermain form sending the current row values}>
<i className="material-icons">edit</i></Link></td>
</tr>
</tbody>
);
});
}
render() {
return (
<div>
<div><h4>User List</h4></div><hr />
<table className="bordered highlight responsive">
<thead>
<tr>
<td>Email</td>
<td>First Name</td>
Action
{this.renderUsers()}
</table>
);
}
}
function mapStateToProps({ users}) {
return { users };
}
export default connect(mapStateToProps, { fetchUsers })(UserList);
My User.js form
const User = () => {
return(
<UserList />
<div className="fixed-action-btn">
<Link to="user/new" className="btn-floating btn-large waves-effect waves-light red">
<i className="material-icons">add</i>
</Link>
</div>
</div>
);
};
export default User;
My UserMain.js form
class UserMainForm extends Component {
renderFields() {
return _.map(userFields, ({ label, name }) => {
return (
<Field
key={name}
component={UserField}
label={label}
name={name}
/>
);
});
}
render() {
return (
<div className="container" style={{marginBottom:'5px'}}>
<div><h4>User Main { mode Edit/New}</h4></div><hr />
<form className="container" onSubmit={this.props.handleSubmit(() =>
this.props.submitUser(this.props.usermainForm.values,this.props.history))}>
<div className="row">
{this.renderFields()}
</div>
<Link to="/register/user" className="red btn-flat white-text">
Cancel
</Link>
<button type="submit" className="waves-effect waves-teal teal btn-flat right white-text">
Save
<i className="material-icons right">done</i>
</button>
</form>
</div>
);
}
}
export default reduxForm({
validate,
form: 'usermainForm',
destroyOnUnmount: false
})(UserMainForm);
Related
Could anyone help me out here please, all I'm trying to do here is to show popup modal confirmation for delete action, but every time I clicked on **Yes **btn to confirm my delete action the last product on the list always get deleted instead. I need help from anyone please?
Here is my code for handling the delete popup
```
//OPEN DELETE MODALS
const [openDeleteModal, isOpenDeleteModal] = useState(false);
const closeDeleteModal = () => {
isOpenDeleteModal(false);
document.body.style.overflow = "unset";
};
const showDeleteModal = () => {
isOpenDeleteModal(true);
};
```
and here is the api
```
//DELETE PRODUCT
const deleteHandler = async (product) => {
try {
await axios.delete(`/api/products/${product._id}`, {
headers: { Authorization: `Bearer ${userInfo.token}` },
});
toast.success("product deleted successfully", {
position: "bottom-center",
});
dispatch({ type: "DELETE_SUCCESS" });
} catch (err) {
toast.error(getError(err), { position: "bottom-center" });
dispatch({ type: "DELETE_FAIL" });
}
};
```
down here is my modal for confirmation
```
{/* MODAL */}
{openDeleteModal && (
<div className="delete-modal">
<div className="delete-modal-box">
<div className="delete-modal-content">
<p className="delete-modal-content-p">
Are you sure to delete this product?
</p>
<div className="delete-modal-btn">
<button
onClick={closeDeleteModal}
className="delete-modal-btn-close"
>
Close
</button>
<button
onClick={() => {
deleteHandler(product);
closeDeleteModal();
}}
className="delete-modal-btn-yes"
>
{" "}
Yes
</button>
</div>
</div>
</div>
</div>
)}
```
All I'm trying to do is to be able to delete any product from the list not the last product every time.
here is the entirety of my productList map looks like
{products?.map((product, index) => (
<tr className="product-item-list" key={index}>
<tr>
<td className="product-item-id">{product._id}</td>
<td className="product-item-name">
{product.name}
</td>
<td className="product-item-price">
£{product.price}
</td>
<td className="product-item-category">
{product.category?.map((cat, index) => (
<span key={index}>{cat}</span>
))}
</td>
<td className="product-item-size">
{product.size?.map((s, index) => (
<span key={index}>{s} </span>
))}
</td>
<td className="product-btn-view">
<button
className="product-btn"
onClick={() =>
navigate(`/admin/productedit/${product._id}`)
}
>
Edit
</button>
<DeleteOutline
className="product-delete"
onClick={showDeleteModal}
/>
{/* MODAL */}
{openDeleteModal && (
<div className="delete-modal">
<div className="delete-modal-box">
<div className="delete-modal-content">
<p className="delete-modal-content-p">
Are you sure to delete this product?
</p>
<div className="delete-modal-btn">
<button
onClick={closeDeleteModal}
className="delete-modal-btn-close"
>
Close
</button>
<button
onClick={() => {
deleteHandler(product);
closeDeleteModal();
}}
className="delete-modal-btn-yes"
>
{" "}
Yes
</button>
</div>
</div>
</div>
</div>
)}
</td>
</tr>
<tr></tr>
</tr>
))}
I guess it happens because all of your modals open when you call showDeleteModal
And the last one is on the top, so when you click to delete the last closure works. Maybe its nessesary to pass id of product into the openDeleteModal. And than check if product.id equals to openDeleteModal.
Can you print to console the product.id when you click on the "Delete" button and check is it the correct id of the clicked product?
I am working on a React project that I have to show content and hide the content conditionally when I click the button. For example, I have four buttons, First Button is Frontend, Second Button is Middleware, Third Button is Database, and Fourth Button is Apps.
By Default when I landed on the Home Page Frontend Button should be Highlighted remaining button should be normal. At that time I have to show only Frontend-related frameworks or libraries.
Now when I click Middleware Button then the Middleware Button should be Highlighted At that time I have to show Middleware Frameworks like Node Express etc.
Now when I click Database Button then the Database Button should be Highlighted At that time I have to show Database like Mongo Db, Casandra.
Now when I click Apps Button then the App Button should be Highlighted At that time I have to show Apps like React native, Flutter.
Please help me to achieve this task
This is Home.js
import React, { useState } from 'react';
import './Home.css'
const Home = () => {
return (
<div className='container'>
<div className='row'>
<div className='col-3'>
<button className='btn btn-primary mt-3'>Frontend</button>
</div>
<div className='col-3'>
<button className='btn btn-danger mt-3'>Middleware</button>
</div>
<div className='col-3'>
<button className='btn btn-secondary mt-3'>Database</button>
</div>
<div className='col-3'>
<button className='btn btn-info mt-3'>Apps</button>
</div>
</div>
<div className='row mt-3'>
<div className='col-3'>
<h3>React</h3>
</div>
<div className='col-3'>
<h3>Angular</h3>
</div>
<div className='col-3'>
<h3>Vue</h3>
</div>
<div className='col-3'>
<h3>Ember</h3>
</div>
</div>
</div>
)
}
export default Home
const Home = () => {
const [selected, setSelected] = useState('frontend')
const frontends = ['React', 'Angular', 'Vue']
const middlewares = ['Node', 'Express', 'Hapi']
const databases = ['MongoDB', 'MySQL', 'Casandra']
const apps = ['React Native', 'Flutter']
let showingArr = []
if (selected === 'frontend') {
showingArr = frontends
} else if (selected === 'middleware') {
showingArr = middlewares
} else if (selected === 'database') {
showingArr = databases
} else if (selected === 'apps') {
showingArr = apps
}
return (
<div className='container'>
<div className='row'>
<div className='col-3'>
<button
className='btn btn-primary mt-3'
onClick={() => setSelected('frontend')}
>Frontend</button>
</div>
<div className='col-3'>
<button
className='btn btn-danger mt-3'
onClick={() => setSelected('middleware')}
>Middleware</button>
</div>
<div className='col-3'>
<button
className='btn btn-secondary mt-3'
onClick={() => setSelected('database')}
>Database</button>
</div>
<div className='col-3'>
<button
className='btn btn-info mt-3'
onClick={() => setSelected('apps')}
>Apps</button>
</div>
</div>
<div className='row mt-3'>
{
showingArr.map(item => (
<div className='col-3'>
<h3>{item}</h3>
</div>
))
}
</div>
</div>
)
}
const [show, setShow] = useState(false);
return(
{show ? <content to show when state is true /> : null}
)
here is a more scale able way of doing this . in the future if you want to add new topics of different types for example Pythonwhich can be of type AI , you want have to add an other condition check you can just add your AI toggle button and set onClick as toggleListType('AI')
import React, { useState ,useEffect} from 'react';
import './Home.css'
const Home = () => {
const [listOFtopics,setlistOFtopics]=useState([
{type:'FRONTEND',title:'react'},
{type:'FRONTEND',title:'angular'},
{type:'MIDDLEWEAR',title:'node'},
{type:'MIDDLEWEAR',title:'express'},
])
const [listOFtopicsToDisplay,setlistOFtopicsToDisplay]=useState([])
useEffect(()=>{
//initializing listOFtopicsToDisplay to show FRONEND related topics
setlistOFtopicsToDisplay(listOFtopics.filter(t=> t.type =="FRONTEND"))
},[])
const toggleListType=(type)=>{
setlistOFtopicsToDisplay(listOFtopics.filter(t=> t.type ==type))
}
return (
<div className='container'>
<div className='row'>
<div className='col-6'>
<button onClick={e=>toggleListType('FRONTEND')} className='btn btn-primary mt-3'>Frontend</button>
</div>
<div className='col-6'>
<button onClick={e=>toggleListType('MIDDLEWEAR')} className='btn btn-danger mt-3'>Middleware</button>
</div>
</div>
<div className='row mt-3'>
{
listOFtopicsToDisplay.map(t=><div className='col-3'><h3>Vue</h3</div>)
}
</div>
</div>
)
}
export default Home
How can we list data from the array list on the same page in button click using react?
When user enter quantity setting value text box change event
class ProductList extends Component {
constructor(props) {
super(props);
this.state={
CartArray:[],
ProductList:[],
}
}
handleInputChange = event =>
{
const cart_values = event.target.name.split('-');
let newCart = {};
newCart["Key"]=cart_values[0]
newCart["ProductName"]=cart_values[1]
newCart["ProductBrand"]=cart_values[2]
this.setState(prevState => ({CartArray: [...prevState.CartArray, newCart]}))
}
viewCart = () => {
//What need to write here show data from CartArray:[] to my basket
}
}
Below is my render method. Numerical text box change i am setting in state value
render() {
return (
<div className="card" style={{ marginBottom: "10px"}}>
<div> <button className="btn btn-sm btn-warning float-right" onClick={this.viewCart}>View cart</button></div>
{this.state.ProductList.map((product, key) =>(
<div className="card-body">
<div className="card-title" key={key} value={key}>{product.ProductName}
<img src= {`data:image/jpeg;base64,${product.Image2}`} width="200" height="80" />{product.Brand}
<div>
<button className="btn btn-sm btn-warning float-right"
onClick={this.addToCart}>Add to cart</button>
<div>
<input type="number" min="0" pattern="[0-9]*" onInput={this.handleInputChange.bind(this)} name={`Name${key}-${product.ProductName}-${product.Brand}`} />
</div>
</div>
</div>
</div>
))}
</div>
)
}
If by show you mean to show on screen, not inside viewCart but in separate method render()
render(){
return(
<div>
{
this.state.CartArray.map((product) => {
<p>Key: {product.Key} </p>
<p>ProductName: {product.ProductName} </p>
<p>ProductBrand: {product.ProductBrand} </p>
})
}
</div>
);
}
I'm making a page where I need to make multiple selections of buttons (like a filter, which I'll use for the next page).
the information from these buttons is coming from an array and I'm using .map () to mount the button list.
My problem is how do I change the state of only the button that was clicked. The way it is now, when I click, all the buttons are active.
How can I solve this?
Thank you.
import React from 'react';
import { Link } from 'react-router-dom';
import { FormattedMessage } from 'react-intl';
import messages from './messages';
import { getLevel, getDiscipline } from '../../functions';
import template from './index.pug';
export default class ConfigAssessment extends React.PureComponent { // eslint-disable-line react/prefer-stateless-function
constructor(props){
super(props);
this.state = {
level: getLevel(),
discipline: getDiscipline(),
active: '',
first_click: true,
}
}
changeActive = () => {
if (this.state.first_click === true) {
this.setState({
active: 'active',
first_click: false
});
} else {
this.setState({
active: '',
first_click: true,
});
}
}
render() {
return(
<div className="configuration">
<div className="config-title">
<i className="ti-settings" />
<h2>
<FormattedMessage {...messages.configAssessment} />
</h2>
</div>
<div className="config-items">
<div className="form-group">
<label>
<FormattedMessage {...messages.level} />
</label>
<div className="row">
{this.state.level.map((level, i) => (
<div className="col-xs-1 col-md-4 col-lg-3" key={level.id}>
<button
className={`btn btn-light-gray btn-block ${this.state.active}`}
id={level.id}
onClick={this.changeActive}
>
{level.level}
</button>
</div>
))}
</div>
</div>
<div className="form-group">
<label>
<FormattedMessage {...messages.discipline} />
</label>
<div className="row">
{ this.state.discipline.map((discipline, i) => (
<div className="col-xs-1 col-md-4 col-lg-3" key={i}>
<button
className={`btn btn-light-gray btn-block ${this.state.active}`}
onClick={this.changeActive}
>
{discipline.discipline}
</button>
</div>
))}
</div>
</div>
<div className="form-group">
<label>
<FormattedMessage {...messages.selectQuestion} />
</label>
<div className="row">
<div className="col-xs-1 col-md-4 col-lg-3">
<button
className={`btn btn-light-gray btn-block ${this.state.active}`}
onClick={this.changeActive}
>
<FormattedMessage {...messages.typeAutomatic} />
</button>
</div>
<div className="col-xs-1 col-md-4 col-lg-3">
<button
className={`btn btn-light-gray btn-block ${this.state.active}`}
onClick={this.changeActive}
>
<FormattedMessage {...messages.typeManual} />
</button>
</div>
</div>
</div>
<div className="form-group fg-right">
<Link className="btn btn-warning" to="#">
<FormattedMessage {...messages.createAssessment} />
</Link>
</div>
</div>
</div>
);
}
}
Create a separate component for button
class MyButton extends Component {
constructor(props){
super(props);
this.state = {
person: this.props.person
}
}
buttonActiveHandler = () => {
let oldStatus = this.props.person.status;
this.props.person.status = (!oldStatus ? 'active': '');
this.setState({
person:this.props.person
});
}
render() {
return (
<button className={this.state.person.status} onClick={this.buttonActiveHandler}>{this.state.person.name}</button>
);
}
}
export default MyButton;
Then import button component. use map function to for your code block
<div className={classes.Box}>
<h4>Lorem, ipsum.</h4>
{
this.props.survey.map((person, i) => {
return (
<MyButton key={i} person={person}/>
)
})
}
</div>
The easiest solution to this problem is making the component of the content inside the map and then handling the state of that component there. Hence it will maintain individual states.
It depends what you need.
You can create separate component for button with state.
You can also keep state of each button in react state as an array, and then you can get the state of each button by index.
I'd recommend the first solution, it'd easier to manage such state, but it will be harder to get the state of a specific button from the parent component.
I have this code to push new FieldArray every time I click the button, but it is only applicable inside renderContract FieldArray component.
const renderContact = ({ fields, meta: { error } }) => (
<div>
{fields.map((contact, index) => (
<div key={index}>
<div className="row form-pad">
<div className="col-md-3">
<span>Country Code {index + 1}:<span className="requiredField text-danger"> * </span>: </span>
</div>
<div className="col-md-7">
<Field name={`${contact}.landlineCountryCode`} component={renderField}type="text"/>
</div>
</div>
</div>
))}
<button className="btn btn-primary" onClick={() => fields.push({})}>
Add Contact
</button>
</div>
)
and render it like this on parent form component:
<FieldArray name="contact" component={renderContact} />
How can I use fields.push({}) outside fieldArray?
EDIT:
I tried this but to no avail:
<button type="button" onClick={() => props.dispatch(arrayPush('PersonalInfoForm', 'contact', [{}]))}> Add Contact</button>
You can dispatch an action arrayPush with the form and the fieldname to effect a fields.push({}) from outside the FieldArray
import { arrayPush } from 'redux-form';
// ...
dispatch(arrayPush('myForm', 'contact', {}));