How to push new FieldArray from outside render function? - reactjs

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', {}));

Related

onClick load react component in the same place

I have a panel with 3 buttons, i want to make onclick on every button, a different component will appear in the same place. How can this logic be done?
<AddNotification />
<EditNotification />
<DeleteNotification />
const AdminPanel = () => {
return (
<Card className={classes.input}>
<div><h1>Notification Panel</h1></div>
<form>
<div className="form-group">
<Button type="submit">Add Notification</Button>
</div>
<div className="form-group">
<Button type="submit">Edit Notification</Button>
</div>
<div className="form-group">
<Button type="submit">Delete Notification</Button>
</div>
</form>
</Card>
)
}
#MLDC No i don't have another divs, i want to replace the buttons with the crossponding component. For example: onclick on Add, then Add component will appears instead of the buttons.
In that case, create a boolean state for every Panel that you have (I created 3 so that you could open the panels simultaneously),
const [isAddPanelOpen, setIsAddPanelOpen] = useState(false);
const [isEditPanelOpen, setIsEditPanelOpen] = useState(false);
const [isDeletePanelOpen, setIsDeletePanelOpen] = useState(false);
Next, apply this to every button
<Button onClick={setIsAddPanelOpen(prevState=>!prevState)}>Add Notification</Button>
<Button onClick={setIsEditPanelOpen(prevState=>!prevState)}>Edit Notification</Button>
<Button onClick={setIsDeletePanelOpen(prevState=>!prevState)}>Delete Notification</Button>
Lastly, Refactor your html to
<div className="form-group">
{isAddPanelOpen ? <AddNotification/> : <Button type="submit">Add Notification</Button>}
</div>
<div className="form-group">
{isEditPanelOpen ? <EditNotification/> : <Button type="submit">Edit Notification</Button>}
</div>
<div className="form-group">
{isDeletePanelOpen ? <DeleteNotification/> :<Button type="submit">Delete Notification</Button>}
</div>
Try this if you want to display one component at a time and hide the others when you click a button
const AdminPanel = () => {
const [componentToDisplay, setComponentToDisplay] = useState("")
return (
<>
<Card className={classes.input}>
<div><h1>Notification Panel</h1></div>
<form>
<div className="form-group">
{componentToDisplay !== "add ? (
<Button type="submit" onCLick={() => setComponentTodisplay("add")}>Add Notification</Button>)
:(<AddNotification />)}
</div>
<div className="form-group">
{componentToDisplay !== "edit ? (
<Button type="submit" onCLick={() => setComponentTodisplay("edit")}>Edit Notification</Button>)
:(<EditNotification />)}
</div>
<div className="form-group">
{componentToDisplay !== "delete ? (
<Button type="submit" onCLick={() => setComponentTodisplay("delete")}>Delete Notification</Button>)
:(<DeleteNotification />)}
</div>
</form>
</Card>
</>
)
}
Or if you want to be able to replace every buttons, use this logic with one state per button
const AdminPanel = () => {
const [addNotif, setAddNotif] = useState(false)
const [editNotif, setEditNotif] = useState(false)
const [deleteNotif, setDeleteNotif] = useState(false)
return (
<>
<Card className={classes.input}>
<div><h1>Notification Panel</h1></div>
<form>
<div className={`form-group ${editNotif || deleteNotif ? "display: none" : "display: flex"}`}>
{!addNotif ? (
<Button type="submit" onCLick={() => setAddNotif(true)}>Add Notification</Button>)
:(<AddNotification setAddNotif={setAddNotif} />)}
</div>
<div className={`form-group ${addNotif || deleteNotif ? "display: none" : "display: flex"}`}>
{!editNotif ? (
<Button type="submit" onCLick={() => setEditNotif(true)}>Edit Notification</Button>)
:(<EditNotification setEditNotif={setEditNotif} />)}
</div>
<div className={`form-group ${addNotif || editNotif ? "display: none" : "display: flex"}`}>
{!deleteNotif ? (
<Button type="submit" onCLick={() => setDeleteNotif(true)}>Delete Notification</Button>)
:(<DeleteNotification setDeleteNotif={setDeleteNotif} />)}
</div>
</form>
</Card>
</>
)
}
Then in your component
const AddNotification = ({setAddNotif}) => {
...
return (
...
<button onCLick={() => setAddNotif(false)}>back</button>
...
)
}
Same logic for the other components
To achieve this logic you need to manage which component is displayed using a state.
This means:
Attribute an arbitrary id to each component.
Store the id of the active component in a useState hook.
Use conditional rendering to display the component that match the current state.
Update the state to the corresponding Id when clicking on each button.
A small example
const [activePanel, setActivePanel] = React.useState(0)
let currentPanel = <Panel0 />
switch(activePanel){
case 0:
currentPanel = <PanelO />
case 1:
currentPanel = <Panel1 />
// Continue as needed
}
return (
<div>
<CurrentPanel/>
<button onClick={() => setActivePanel (0)}> Panel 0 </button>
<button onClick={() => setActivePanel (1)}> Panel 1 </button>
// And so on
</div>
)
You can further refine this by extracting the switch statement into its own component that takes the activePanel as a prop.

button Onclick call the function with React State

I am new to react,
I am trying to pass the values on the button onclick from one component to another.
Here is my following code:
contact Component:
import React,{useState} from 'react';
import Section from '../../../HOC/Section';
import apicall from '../../UI/JS/allapicall.js';
const Contact = () => {
const [name, setName] = useState(0);
console.log("name");
return (
<Section id='contact'>
<div className='container pt-2 pb-5'>
<div className='section-header pt-5 pb-5 text-center'>
<h3 className='section-title'>
<span>Get in touch with </span>Us
</h3>
<h6 className='section-subtitle mr-auto ml-auto'>
We are here with you
</h6>
</div>
<div className='section-content'>
<div className='row'>
<div className='col-md-9 col-lg-7 mr-auto ml-auto'>
{/* <form> */}
<div className='form-group'>
<input
type='text'
className='form-control rounded-0'
aria-describedby='emailHelp'
placeholder='Enter Name...'
onChange={e=>setName(e.target.value)}
/>
</div>
<div className='form-group'>
<input
type='email'
className='form-control rounded-0'
aria-describedby='emailHelp'
placeholder='Enter email...'
/>
</div>
<div className='form-group'>
<textarea
className='form-control rounded-0'
rows='5'
placeholder='Enter Message...'
/>
</div>
<div className='form-group text-center'>
<button className='btn btn-block btn-primary rounded-0 mr-auto ml-auto' onClick={apicall({name})}>
Send
</button>
</div>
{/* </form> */}
</div>
</div>
</div>
</div>
</Section>
);
};
export default Contact;
apicall.js:
export default function messagesubmit(test)
{
console.log(test);
const axios = require('axios');
// Optionally the request above could also be done as
axios.get('https://www.zohoapis.com/crm/v2/functions/ticket_create/actions/execute?auth_type=apikey', {
params: {
zapikey: "1003.9145fb5d691b5f95a194c17e56300ed3.1cc7246813d8d6842c47f543a4f50b8f"
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
})
.then(function () {
// always executed
});
}
Currently:
For each state changes(when I change the "Value" of the text field) the onClick button function is calling on react, and the console.log(test); is printing for every change in name, I don't know where I am doing wrong I need to trigger it on only onclick event.
Here is what I wanted:
For each field value, I need to store the values in states.
On button Click I need to pass the stored values in the state to message submit function within an argument,
Thanks in advance
<button className='btn btn-block btn-primary rounded-0 mr-auto ml-auto' onClick={apicall({name})}>
Send
</button>
Change this to:
<button className='btn btn-block btn-primary rounded-0 mr-auto ml-auto' onClick={() => apicall({name})}>
Send
</button>
Your button's onClick needs to be () => apicall({name}) instead of just apicall({name}). When you set the onClick to be apicall({name}) then what happens is apicall({name}) gets instantly called and the onClick is set to the result of that call.

How to show the content and hide the content conditionally in react using hooks

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

Append data in same page in button click with react Js

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>
);
}

How to change the state of an item affected by onClick in array?

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.

Resources