I would like to delete a search result by clicking on the X icon on the individual card.
The search returns 10 recipes from the API, generating 10 divs. How would I go about removing individual divs onClick of the icon whilst keeping the other divs? Essentially just a remove search result button.
return (
<div className='App'>
<form onSubmit={getSearch} className="search-form">
<InputGroup>
<InputGroupAddon addonType="prepend">
<InputGroupText><FontAwesomeIcon icon={faSearch} /></InputGroupText>
</InputGroupAddon>
<Input className="search-bar" type="text" placeholder="Search for recipe..." value={search} onChange={updateSearch} />
</InputGroup>
<Button color="primary" size="sm" className="search-button" type="submit">Search</Button>
</form>
<div className="recipes">
{recipes.map(recipe => (
<Recipe
key={recipe.recipe.label}
title={recipe.recipe.label}
theUrl={recipe.recipe.url}
image={recipe.recipe.image}
ingredients={recipe.recipe.ingredients}
source={recipe.recipe.source}
healthLabels={recipe.recipe.healthLabels}
servings={recipe.recipe.yield} />
))}
</div>
</div>
const Recipe = ({ title, theUrl, image, ingredients, source, healthLabels, servings }) => {
return (
<div className={style.recipe}>
<FontAwesomeIcon className={style.delete} icon={faTimes} />
<h3 >{title}</h3>
<Badge className={style.badge} color="primary">{source}</Badge>
<p>Serves: <Badge color="primary" pill>{servings}</Badge></p>
<img src={image} alt='food' />
<ol className={style.allergens}>
{healthLabels.map(healthLabel => (
<li>{healthLabel}</li>
))}
</ol>
<div className={style.ingr}>
<ol>
{ingredients.map(ingredient => (
<li>{ingredient.text}</li>
))}
</ol>
<Button className={style.button} outline color="primary" size="sm" href={theUrl} target="_blank">Method</Button>
</div>
<div className={style.info}>
<div className={style.share}>
<WhatsappShareButton url={theUrl}><WhatsappIcon round={true} size={20} /></WhatsappShareButton>
<FacebookShareButton url={theUrl}><FacebookIcon round={true} size={20} /></FacebookShareButton>
<EmailShareButton url={theUrl}><EmailIcon round={true} size={20} /></EmailShareButton>
</div>
</div>
</div>
);
}
Simply update the recipes array and React will update the HTML.
I'm not sure where recipes comes from, but if you set an onClick on, say, <Recipe label="x"> that deletes the corresponding recipe element from recipes, then React should no longer render that recipe.
That should be easy. Here's one way:
add onClick to this
<FontAwesomeIcon onClick={deleteRecipe} className={style.delete} icon={faTimes} />
pass a reference of the function that deletes the recipe.
deleteRecipeHandler = (id) => {
// filter your recipes here such that the new recipes array doesn't contain the recipe
// with the id you're getting here.
// Change the below code how you need
const newRecipes = oldRecipes.filter(recipe => {
return recipe.id !== id;
});
}
{recipes.map(recipe => (
<Recipe
key={recipe.recipe.label}
deleteRecipe={this.deleteRecipeHandler.bind(this,recipe.recipe.id)}
title={recipe.recipe.label}
theUrl={recipe.recipe.url}
image={recipe.recipe.image}
ingredients={recipe.recipe.ingredients}
source={recipe.recipe.source}
healthLabels={recipe.recipe.healthLabels}
servings={recipe.recipe.yield} />
))}
since you're destructuring your props you can use
const Recipe = ({ title, theUrl, image, ingredients, source, healthLabels, servings, deleteRecipe }) => {
return (
<div className={style.recipe}>
<FontAwesomeIcon onClick={deleteRecipe} className={style.delete} icon={faTimes} />
Related
so this is my render, it render basically a ui where a username and their email. it also have the option to add new user but when I run the code in my local host, i get this error in my console: Warning: Each child in a list should have a unique "key" prop.
render() {
return (
<div className="App">
{this.state.users.map((user) => {
return (
<React.Fragment>
<div key={user._id} className="box">
<h3>{user.name}</h3>
<h4>{user.email}</h4>
<button
onClick={() => {
this.beginEdit(user);
}}
>
Update
</button>
<button
onClick={() => {
this.deleteUser(user);
}}
>
Delete
</button>
</div>
</React.Fragment>
);
})}
{this.renderAddUser()}
</div>
);
}
}
this is my AddRenderUser
// render new User
renderAddUser() {
return (
<React.Fragment >
<input
type="text"
placeholder="User name"
value={this.state.newUserName}
onChange={this.updateFormField}
name="newUserName"
/>
<input
type="text"
placeholder="User email"
value={this.state.newUserEmail}
onChange={this.updateFormField}
name="newUserEmail"
/>
<button onClick={this.addUser}>Add</button>
</React.Fragment>
);
}
Although I did put the keys props in my div, so not sure how to correct this error
Your key should be in your top-most element
render() {
return (
<div className="App">
{this.state.users.map((user) => {
return (
<React.Fragment key={user._id}>
<div className="box">
<h3>{user.name}</h3>
<h4>{user.email}</h4>
<button
onClick={() => {
this.beginEdit(user);
}}
>
Update
</button>
<button
onClick={() => {
this.deleteUser(user);
}}
>
Delete
</button>
</div>
</React.Fragment>
);
})}
{this.renderAddUser()}
</div>
);
}
}
You need to add the key prop to the React.Fragment tag like this:
<React.Fragment key={user._id}>
Or please try to use index value instead of user.id as follows:
render() {
return (
<div className="App">
{this.state.users.map((user, i) => {
return (
<React.Fragment key={i}>
<div className="box">
<h3>{user.name}</h3>
<h4>{user.email}</h4>
<button
onClick={() => {
this.beginEdit(user);
}}
>
Update
</button>
<button
onClick={() => {
this.deleteUser(user);
}}
>
Delete
</button>
</div>
</React.Fragment>
);
})}
{this.renderAddUser()}
</div>
);
}
I have the ability to render my single button with all my options inside of the one button like this:
What I want to do is separate these into individual buttons
My code is as follows (the first button is the one in question, how do I make them individual?)
function Filters({ filter, setFilter, location }) {
return (
<div className="bg-transparent outline-none text-sm text-gray-600 placeholder-grey-400">
<div className="pl-2 pr-2 gap-3">
<Button
colorScheme="teal"
size="xs"
onClick={(e) => {
setFilter({
...filter,
search: e.target.value,
});
}}
>
{locations.map((item, index) => (
<text>
<option key={index} value={item.location}>
{item.location}
</option>
</text>
))}
</Button>
<Button
colorScheme="teal"
size="xs"
onClick={(e) => {
setFilter({
...filter,
search: e.target.value,
});
}}
>
ALL
</Button>
</div>
</div>
);
}
export default Filters;
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>
): "";
I am building header using material UI Tab Component but I see below error:
index.js:2178 Material-UI: The value provided to the Tabs component is invalid.
None of the Tabs' children match with [object Object].
You can provide one of the following values: 0, 1.
I tried console.log the newValue to see what value it is getting and I can see 0 and 1 while navigating through tabs.
Note : Removed Some Code for better visibility
Here is my component:
const Header = (props) => {
const { classes } = props;
const [value, setValue] = useState(0);
const [modalIsOpen, setIsOpen] = React.useState(false);
const openModal = () => {
setIsOpen(true);
};
const closeModal = () => {
setIsOpen(false);
};
const handleTabChange = (event, newValue) => {
console.log(newValue);
setValue({ newValue });
};
return (
<div>
<div className="topnav">
<img src={logo} className="logo" alt="Movies App Logo" />
<div className="topnav-right">
<Button variant="contained" color="default" onClick={openModal}>
Login
</Button>
</div>
<div className="topnav-right">
<Button variant="contained" color="default">
Logout
</Button>
</div>
</div>
<Modal
ariaHideApp={false}
isOpen={modalIsOpen}
onRequestClose={closeModal}
contentLabel="Login"
aria-labelledby="Modal"
aria-describedby="Modal for Login and Registration"
style={customStyles}
>
<Paper className={classes.Paper}>
<CardContent>
<Tabs
className="tabs"
value={value}
onChange={handleTabChange}
centered
>
<Tab label="Login" />
<Tab label="Register" />
</Tabs>
{value === 0 && (
<div>
<FormControl required>
<InputLabel htmlFor="username" className={classes.inputLable}>
Username
</InputLabel>
<Input
className={classes.Input}
id="username"
type="text"
username={username}
onChange={usernameChangeHandler}
/>
<FormHelperText>
<span className="red">required</span>
</FormHelperText>
</FormControl>
<br />
<br />
<FormControl required>
<InputLabel
htmlFor="loginPassword"
className={classes.inputLable}
>
Password
</InputLabel>
<Input
className={classes.Input}
id="loginPassword"
type="password"
password={password}
onChange={passwordChangeHandler}
/>
<FormHelperText>
<span className="red">required</span>
</FormHelperText>
</FormControl>
<br />
<br />
{loggedIn === true && (
<FormControl>
<span className="success-text">Login Successful!</span>
</FormControl>
)}
<br />
<br />
<Button
variant="contained"
color="primary"
onClick={loginHandler}
>
LOGIN
</Button>
</div>
)}
{value === 1 && (
<div>
<h1>something</h2>
</div>
)}
</CardContent>
</Paper>
</Modal>
</div>
);
};
export default withStyles(styles)(Header);
For some reason you enclosed the value in an object (curly braces syntax).
Replace setValue({ newValue }) with setValue(newValue).
https://codesandbox.io/s/qzm5q6xvx4
I've created the above codesandbox. I am using redux-form ([https://redux-form.com]) that where you can add and remove fields to populate the form using .push and .pop 2.
The problem with using .pop it only takes off the last array element, I would like the option for each .push created element to have its own "remove" button, therefore not simply taking the last item off the array.
I assume I would need to assign the .pop to look at the matching react .map element somehow?
const renderForm = ({ fields, label }) => (
<div>
<div
variant="fab"
color="primary"
className="jr-fab-btn"
aria-label="add"
onClick={() => fields.push()}
>
ADD
</div>
<div
variant="fab"
color="primary"
className="jr-fab-btn"
aria-label="add"
onClick={() => fields.pop()}
>
REMOVE
</div>
{fields.map((newIntel, index) => {
console.log("newIntel", newIntel, index);
return (
<Field
name={newIntel}
key={index}
label={label}
placeholder={label}
component={renderTextField}
placeholder={label}
label={label}
/>
);
})}
</div>
);
Any ideas would be welcome.
If you will look into the fields which is a prop to your renderForm, it contains a method remove to remove a specific element. Just pass it the index.
below is modified code-block of your component. I have made it class-component:
class renderForm extends React.Component {
render(){
let {fields, label} = this.props;
const removeName = (index) => {
fields = fields.remove(index);
}
return(
<div>
<div
variant="fab"
color="primary"
className="jr-fab-btn"
aria-label="add"
onClick={() => fields.push()}
>
ADD
</div>
{fields.map((newIntel, index) => {
console.log("newIntel", newIntel, index);
return (
<div>
<Field
name={newIntel}
key={index}
label={label}
placeholder={label}
component={renderTextField}
/>
<p
variant="fab"
color="primary"
style={{'cursor': 'pointer'}}
className="jr-fab-btn"
aria-label="add"
onClick={() => removeName(index)}
>
REMOVE
</p>
</div>
);
})}
</div>
)
}}
Hope, you can understand the code-block easily. Just paste the above code in place of your renderForm component. It will work like magic. :p