Pass value to a modal in jsx map - javascript

I have a map that render few items. How can I pass params like name of the item, id of the item etc to the modal component?
render(){
return(
<div>
<Modal
isOpen={this.state.OpenDeleteModal}
confirmationTitle={`Delete item`}
confirmationCancel={'No'}
confirmationSuccess={'Yes'}
closeModal={this.closeModal}
successModal={this.successModal}
>
<p className="center">Are you sure you want to delete this item?</p>
</Modal>
<div className="wrapper">
{map(items, obj =>
<div key={obj._id} className="panel-body">
<div className="row">
<h2 className="title">{obj.name}</h2>
<a onClick={()=> this.setState({OpenDeleteModal:true})}>Delete</a>
</div>
</div>
)}
</div>
</div>
)
}
I only can think of put the obj._id in the tag as custom attribute and when user click on delete it change the state of the selectedItem, pass it through props.

One simple solution is to remember for which item you have opened the modal. Something like below. Set the selected item when you open the modal. During delete, fetch it from state and delete it.
render(){
return(
<div>
<Modal
isOpen={this.state.OpenDeleteModal}
confirmationTitle={`Delete item`}
confirmationCancel={'No'}
confirmationSuccess={'Yes'}
closeModal={this.closeModal}
successModal={this.successModal}
>
<p className="center">Are you sure you want to delete this item?</p>
</Modal>
<div className="wrapper">
{map(items, obj =>
<div key={obj._id} className="panel-body">
<div className="row">
<h2 className="title">{obj.name}</h2>
<a onClick={()=> this.setState({OpenDeleteModal:true, selectedItem: obj._id})}>Delete</a>
</div>
</div>
)}
</div>
</div>
)
}
UPDATE: Make sure to clear the selectedItem after you close the modal.

A modal can access the state of the react component, you can store the information of the selected link in state
storeInformation(item) {
this.setState({OpenDeleteModal:true,
selectedId: item.id
selectedName: item.name
})
}
render(){
return(
<div>
<Modal
isOpen={this.state.OpenDeleteModal}
confirmationTitle={`Delete item`}
confirmationCancel={'No'}
confirmationSuccess={'Yes'}
closeModal={this.closeModal}
successModal={this.successModal}
>
<p className="center">Are you sure you want to delete this item?</p>
<div>Name is: {this.state.selecteName}</div>
</Modal>
<div className="wrapper">
{map(items, obj =>
<div key={obj._id} className="panel-body">
<div className="row">
<h2 className="title">{obj.name}</h2>
<a onClick={()=> this.storeInformation(obj)}>Delete</a>
</div>
</div>
)}
</div>
</div>
)
}

Related

Add popup in every item of flatlist in React

I would like to add a popup form in each item in the Flatlist, and the item is actually a card.
My problem is that every time, I clicked the button, the popup shows but, when my mouse moves out of the card, instead of showing the original one, it shows another popup whose parent is the whole page.
I know the problem should be that I need not set the variable setPopup properly. But I don't know how to fix it.
When my mouse is on the card:
enter image description here
When my mouse is out of the card, the popup will move up and its position will be based on the whole page:
enter image description here
Thank you!
This is my code.
const [buttonPopUp, setButtonPopUp] = useState(undefined);
const renderItem = (item, index) => {
return(
<Card key={index} style={{width: '20rem'}}>
<CardImg className='galleryPics' top src={galleryPic.img} alt="..."/>
<CardBody>
<PopUpEditGallery
gallery={item}
index = {index}
trigger={buttonPopUp}
setTrigger={setButtonPopUp}
>
Edit
</PopUpEditGallery>
<CardTitle className='cardTitle'>{item.title}</CardTitle>
<CardText className='cardText'>{item.description}</CardText>
<Button className="btn-round btn-icon" color="primary" size='sm' onClick={()=> setButtonPopUp(index)}>Edit</Button>
</CardBody>
</Card>
);
}
return (
<div>
<div>
<Header/>
</div>
<div className="container">
<div className="row">
<div className='col-7'>
<ul>
<FlatList
list={values.gallery}
renderItem={renderItem}/>
</ul>
</div>
</div>
</div>
</div>
)
code for popup
return (props.trigger != undefined) ? (
props.trigger == props.index &&
<div className='popup'>
<div className='popupInner'>
<form onSubmit={handleSubmit(onSubmit)}>
<FormGroup>
<Label>Title</Label>
<Input
type="text"
placeholder={prev.title}
onChange={val => props.setTitle(val.target.value, prev.idx)}
/>
</FormGroup>
<Button className="btn-round btn-icon" color="primary" size='sm'>
Submit
</Button>
<Button className="btn-round btn-icon" color="default" size='sm'>
Cancel
</Button>
</form>
</div>
</div>
): "";

ReactJs force input focus on div button click not working

I'm working on a modal in react where I have to click a button outside an input element and focus the input element and change the value. I set the input element to be disabled on default and for the edit button to remove the disabled property and then focus the element. the element is not getting visible focused neither is the disabled property being removed. It looks like it happens in a split second and then returns back to normal because whenever I check if the element is being focused on my console it displays true but It's not being visible focused.
below is my code
EDIT FUNCTION
const [editState,setEditState] = useState(null)
const editCatName = (e,id)=>{
e.stopPropagation();
setEditState({...editState,id: categories[id].id})
setActiveButton('editcatname');
let row = document.querySelectorAll('.cat-row')[id].querySelector('input');
console.log('row',row)
row.classList.remove('pointer');
row.value='Row value set'
row.hasAttribute('disabled') && row.toggleAttribute('disabled')
row.focus();
console.log(row.value)
}
const [activeButton,setActiveButton] = useState('newproduct');
const ProductCategoryModal = ()=>{
return(
<div
onClick={()=>{setCategoryModal(false)}}
className="_modal fixed " style={{zIndex:'100'}} >
<div
onClick={e=>e.stopPropagation()}
className='wytBg boxRad paddBoth sectPad relative'>
<div>
<div className="flexBtw">
<h3 className="head flexAl">Product Categories</h3>
<div className='head'> <AiOutlinePlus/> </div>
</div>
</div>
<GridStyle className='nestM' gridp='45% 55%' gap='0em'>
<Scrolldiv className='' measure='300px'>
{
categories && categories.length?
categories.map((ctg,key)=>
ctg.name !=='Others' &&
<div key={key}
onClick={(e)=>
fixCategoryDetail(ctg.id,e)
}
className={`cat-row cursor rowws flexBtw ${ key===0 && 'rows-
top'}`}>
<div>
<input
defaultValue={ctg.name}
// disabled
style={{maxWidth:'180px'}}
className={'categoryInput pointer '+ key}
onChange={e=>setEditState({
id:ctg.id,
value:e.target.value
})}
onBlur={e=>{
e.target.value=ctg.name
}}
/>
{/* {ctg.name} */}
</div>
<div className="smallflex hashEdit">
<div>
<BiEditAlt
className='cursor'
FUNCTION TO FOCUS ELEMENT IS HERE
onClick={e=>editCatName(e,key)}
/>
</div>
{
!products.find(prod=>prod.category ===ctg.id) &&
<div className='hash'> <CgClose className='cursor'/> </div>
}
</div>
</div>
):null
}
</Scrolldiv>
<Scrolldiv measure='300px' className='secondRow paddBoth'>
{
categoryDetail.length?
<div className=" search flexC">
<div>
<SearchInputBox
icon={ <CgSearch style={{width:30}} />}
padLeft={'10px'}
className='searchInput smalltxt'
inputPadding='0.5em 0.6em'
// onchange={filterByStarts}
iconPosition
summary='Type or search a product'
options=
{products.filter(prod=>
prod.category===3).map(prod=>prod.name)}
inputClassName={'searchInput smalltxt'}
pad='0'
/>
<div className="nestM flex">
<div measure='150px' >
{
categoryDetail.length?
categoryDetail.map((ctg,key)=>
ctg.category !== 3 &&
<div key={key} className=
{`doubleflex flexBtw smalltxt
itemunits ${key!==0 &&
'smallM'} `}>
<div>{ctg.name}</div>
<div>
<CgClose onClick=
{()=>removeProductFromCategory
(ctg.id,ctg.name)}
className='cursor'/>
</div>
</div>
):null
}
</div>
</div>
</div>
</div>
:null
}
</Scrolldiv>
</GridStyle>
<div className="section flexC">
<button style={{maxWidth:'70%'}}
onClick={()=>
activeButton==='newproduct'?removeProductFromCategory():
activeButton==='addcategory'?createNewCategory():
editCategoryName()}
className="submit-button category-submit">
Update
</button>
</div>
</div>
</div>
)
}

Next js component doesn't show without reload

Basically, I have a nested component that I want to render with the parent component and it's working fine when the server starts.
But the problem arises when I switch back from another page. Some of the nested components get disappeared. If I made a refresh then again everything ok.
How can I solve this issue?
Normal:
Image-1
Component disappeared:
Image-2
Index.js:
import BannerBaseLine from "./../components/HOME/Banner/BannerBaseLine";
import SubSection1 from "./../components/ABOUT/subSection1";
import CoursesList from "../components/HOME/MOSTTRENDING/CoursesList/courseslist";
import ShortOverview from "./../components/HOME/CourseOverviewSection/Section1/shortoverview";
import Testimonial from "./../components/HOME/Testimonial/testimonial";
import ClientItem from "./../components/HOME/Client-area/all-client-item";
export default function HomeMain({categories}) {
return (
<>
<br></br>
<br></br>
<br></br>
<BannerBaseLine categories = {categories} />
<CoursesList />
{/* <SubSection1 /> */}
<ShortOverview />
<CoursesList />
<Testimonial />
<ClientItem />
</>
);
}
export async function getStaticProps(){
const response = await fetch('http://localhost:8000/api/data/categories')
const data = await response.json()
console.log(data)
return {
props:{
categories : data,
}
}
}
BannerBaseLine component:
import BannerBlock from './BannerBlock';
export default function BannerBaseLine({ categories }) {
return (
<>
<section
className="banner-area"
style={{ backgroundImage: "url(assets/img/banner/0.jpg)" }}
>
<div className="container">
<div className="row">
<div className="col-lg-6 col-md-8 align-self-center">
<div className="banner-inner text-md-start text-center">
<h1>
Find the Best <span>Courses</span> & Upgrade{" "}
<span>Your Skills.</span>
</h1>
<div className="banner-content">
<p>
Edufie offers professional training classes and special
features to help you improve your skills.
</p>
</div>
<div className="single-input-wrap">
<input type="text" placeholder="Search your best courses" />
<button>
<i className="fa fa-search"></i>
</button>
</div>
</div>
</div>
</div>
</div>
</section>
<br></br>
<br></br>
<div className="container">
<div className="intro-area-2">
<div className="row justify-content-center">
<div className="col-lg-12">
<div className="intro-slider owl-carousel">
{categories.map((category) => {
return (
<>
<BannerBlock category={category} key={category.id} />
</>
);
})}
</div>
</div>
</div>
</div>
</div>
</>
);
}
BannerBlock component:
export default function BannerBlock({category}) {
console.log(category);
return (
<div className="item">
<div className="single-intro-wrap">
<div className="thumb">
<img src={category.image} alt="img" />
</div>
<div className="wrap-details">
<h6>
{category.Base_Category_Title}
</h6>
<p>236 Course Available</p>
</div>
</div>
</div>
);
}
From https://nextjs.org/docs/basic-features/data-fetching#getstaticprops-static-generation
Note: You should not use fetch() to call an API route in
getStaticProps. Instead, directly import the logic used inside your
API route. You may need to slightly refactor your code for this
approach.
Fetching from an external API is fine!
you should check if categories exist
export default function HomeMain({categories}) {
if(categories){
return <Loading Component />
}
rest of the code...
}

Cards inside the grid-container: each child in a list should have a unique "key" prop

What I`m doing wrong?It also says: "Check the render method of Card" , which is here:
<div className="grid-container">
{pokemonData.map((pokemon, i) => {
console.log(pokemon.id) // unique numbers are here
return <Card key={pokemon.id} pokemon={pokemon} />
})}
</div>
Card component itself:
function Card({ pokemon }) {
return (
<div className="card">
<div className="card__image">
<img src={pokemon.sprites.front_default} alt="Pokemon" />
</div>
<div className="card__name">
{pokemon.name}
</div>
<div className="card__types">
{
pokemon.types.map(type => {
return (
<div className="card__type" style={{backgroundColor: typeColors[type.type.name]}}>
{type.type.name}
</div>
)
})
}
</div>
<div className="card__info">
<div className="card__data card__data--weight">
<p className="title">Weight:</p>
<p>{pokemon.weight}</p>
</div>
<div className="card__data card__data--height">
<p className="title">Height:</p>
<p>{pokemon.height}</p>
</div>
<div className="card__data card__data--ability">
<p className="title">Abilities:</p>
{/* {console.log(pokemon.abilities)} Temporary for dev puprose */}
{pokemon.abilities.map(ability => <p>{ability.ability.name}</p>
)}
</div>
</div>
</div>
);
}
export default Card;
You can use the index of the array may be your data is having some kind of duplicate. It is recommended that you pass a key prop whenever you are returning a list.
<div className="grid-container">
{pokemonData.map((pokemon, i) => {
console.log(pokemon.id) // unique numbers are here
return <Card key={i} pokemon={pokemon} />
})}
</div>
Equally, check this segment of card components.
{
pokemon.types.map((type,i) => {
return (
<div key={i} className="card__type" style={{backgroundColor:
typeColors[type.type.name]}}>
{type.type.name}
/div>
)
})
}
And
<div className="card__data card__data--ability">
<p className="title">Abilities:</p>
{/* {console.log(pokemon.abilities)} }
{pokemon.abilities.map((ability, i) => <p key={i}>{ability.ability.name}
</p>
)}
</div>
Previous answer will solve your problem. However, for your info, I would also like to add here.
For React a key attribute is like an identity of a node/element/tag which helps React to identify each item in the list and apply reconciliation correctlyon each item. Without a key React will render your component but may cause issue when you re-order your list.
React recommends to use id of the data instead of index number. However, if your list does not re-orders/ sorts or do not have id then you can use index.
You can read more here:
https://reactjs.org/docs/lists-and-keys.html
Change this:
<div className="card__types">
{
pokemon.types.map(type => {
return (
<div className="card__type"
style={{backgroundColor:typeColors[type.type.name]}}
>
{type.type.name}
</div>
)
})
}
</div>
to:
<div className="card__types">
{
pokemon.types.map((type, key) => {
return (
<div key={key} className="card__type"
style={{backgroundColor:typeColors[type.type.name]}}
>
{type.type.name}
</div>
)
})
}
</div>
and:
{pokemon.abilities.map(ability => <p>{ability.ability.name}</p>
to:
{pokemon.abilities.map((ability,key) => <p key={key} >{ability.ability.name}</p>

How to dynamically render the user data in a component on button click in React

I'm new in React and got stuck on how can I achieve this.
After the user fills the field CEP from the first card and click on the button 'Gravar Dados', it shows a second card with all the information from the first card.
Template Picture:
New Result Picture:
What I need is dynamically create another card, under the second card with new info from the first card.
This is what I've done so far.
I have this component DadosPessoais.js which is the second card in the Template Picture:
render() {
return (
<div className="card shadow mt-5" >
<div className="card-header">
<span>Dados Pessoais </span>
</div>
<div className="card-body">
<div className="row">
<div className="col-4">
<div>
<span>Cep: <strong>{this.props.cep}</strong></span>
</div>
<div>
<span>Bairro: <strong>{this.props.bairro}</strong></span>
</div>
</div>
<div className="col-5">
<div>
<span>Rua: <strong>{this.props.rua}</strong></span>
</div>
<div>
<span>Cidade: <strong>{this.props.cidade}</strong></span>
</div>
</div>
<div className="col-3">
<div>
<span>UF: <strong>{this.props.uf}</strong></span>
</div>
</div>
</div>
</div>
</div>
);
}
In my Home.js I have a form with onSubmit that calls mostrarDadosPessoais function:
Function:
mostrarDadosPessoais(e) {
e.preventDefault();
this.setState({
listaDados: this.state.listaDados.concat({
cep: e.target.value,
rua: e.target.value,
bairro: e.target.value,
cidade: e.target.value,
uf: e.target.value,
}),
});
}
And my input components UserInput, Should it be like this?:
<div className="col-3">
<UserInput name="Rua" Label="Rua" Id="Rua" value={this.state.rua} Disabled />
</div>
<div className="col-3">
<UserInput name="Bairro" Label="Bairro" Id="Bairro" value={this.state.bairro} Disabled />
</div>
<div className="col-3">
<UserInput name="Cidade" Label="Cidade" Id="Cidade" value={this.state.cidade} Disabled />
</div>
<div className="col-1">
<UserInput name="UF" Label="UF" Id="UF" value={this.state.uf} Disabled />
</div>
And to show the result card I've done this:
<div className="col-md-4">
{this.state.listaDados.length === 0
? null
: this.state.listaDados.map((lista) => (<DadosPessoais {...lista} />))}
</div>
This is my state:
this.state = {
listaCidade: [],
listaDados: [],
}
Any ideas on how can I create another component and keep the values from the first one?
Thank you.
If I understand well, you need a list of elements, displayed on the right, that will show user-entered data. You need the user to be able to enter many addresses through the form on the left, and you want each address to display on the right.
I would solve this with a component that contains state for all the elements you need to display in an array that you update on a form submit event, because that's an easy event to work with when you have forms with lots of fields. You can grab the values of the components through the event object e.
class StateContainer extends Component {
constructor() {
super(props);
this.state = {
addresses: [],
}
}
mostrarDadosPessoais(e) {
e.preventDefault();
this.setState({
listaDados: this.state.listaDados.concat({
cep: e.target.cep.value,
rua: e.target.rua.value,
// etc, etc
}),
})
}
render() {
return (
<div>
<form handleSubmit={this.mostrarDadosPessoais}>
{/* left-side form */}
<input name="msg" />
<button type="submit"></button>
</form>
<div>
{/* right-side list of elements */}
{this.state.addresses.length === 0
? null
: this.state.addresses.map(
(address) => (<DadosPessoais {...address} />)
)
}
</div>
</div>
);
}
}

Categories

Resources