I am trying to get an input field to appear when the user selects ‘other’ from the drop down menu. It was only appearing when I first got on the add recipes page, but I changes a few lines and then it stopped appearing all together. I am using FLask for the backend and it is pulling the cuisines from a database.
import React, { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
function AddRecipe() {
const navigate = useNavigate();
const [formData, setFormData] = useState({
name: '',
description: '',
ingredients: '',
directions: '',
prep_time: '',
total_servings: '',
image: '',
cuisine_id: '',
user_id: '',
});
const [cuisines, setCuisines] = useState([]);
const [otherCuisineName, setOtherCuisineName] = useState('');
const [selectedCuisine, setSelectedCuisine] = useState('');
const [successMessage, setSuccessMessage] = useState('');
useEffect(() => {
fetchCuisines();
}, []);
const fetchCuisines = async () => {
try {
const response = await fetch('/api/cuisines');
const data = await response.json();
setCuisines(data);
} catch (error) {
console.error('Error fetching cuisines:', error);
}
};
const handleInputChange = (e) => {
const { name, value } = e.target;
setFormData({ ...formData, [name]: value });
};
const handleCuisineChange = (e) => {
const value = e.target.value;
console.log("Selected cuisine:", value);
setSelectedCuisine(value);
if (value === 'Other') {
setOtherCuisineName('');
document.getElementById('other-cuisine-input').style.display = 'block';
} else {
document.getElementById('other-cuisine-input').style.display = 'none';
}
};
const handleOtherCuisineNameChange = (e) => {
setOtherCuisineName(e.target.value);
};
const handleSubmit = async (e) => {
e.preventDefault();
let cuisineId;
if (selectedCuisine === 'Other') {
try {
const response = await fetch('/api/cuisines', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ name: otherCuisineName }),
});
const data = await response.json();
cuisineId = data.id;
} catch (error) {
console.error('Error creating new cuisine:', error);
}
} else {
cuisineId = selectedCuisine;
}
// Retrieves cuisine id
formData.cuisine_id = cuisineId;
try {
const response = await fetch('/api/recipes', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(formData),
});
const data = await response.json();
console.log('Recipe created:', data);
setSuccessMessage(`${formData.name} added!`);
setFormData({
name: '',
description: '',
ingredients: '',
directions: '',
prep_time: '',
total_servings: '',
image: '',
cuisine_id: '',
user_id: '',
});
navigate('/recipes')
} catch (error) {
console.error('Error creating recipe:', error);
}
};
return (
<div className="addrecipe">
<h2>Add Recipe</h2>
<form onSubmit={handleSubmit}>
<div className="addrecipe-card">
{successMessage && <p>{successMessage}</p>}
<label>Name:</label>
<input
type="text"
name="name"
placeholder="recipe name"
value={formData.name}
onChange={handleInputChange}
required
/>
<div>
<label>Description:</label>
<textarea
name="description"
placeholder="brief recipe description"
value={formData.description}
onChange={handleInputChange}
required
/>
</div>
<div>
<label>Ingredients:</label>
<textarea
name="ingredients"
placeholder="recipe ingredients separated by commas"
value={formData.ingredients}
onChange={handleInputChange}
required
/>
<label>Directions:</label>
<textarea
name="directions"
placeholder="recipe directions separated by periods."
value={formData.directions}
onChange={handleInputChange}
required
/>
</div>
<div>
<label>Prep Time (minutes):</label>
<input
type="number"
name="prep_time"
placeholder="approximate prep time"
value={formData.prep_time}
onChange={handleInputChange}
required
/>
</div>
<div>
<label>Total Servings:</label>
<input
type="number"
name="total_servings"
placeholder="total servings"
value={formData.total_servings}
onChange={handleInputChange}
required
/>
</div>
<div>
<label>Image Link:</label>
<input
type="text"
name="image"
value={formData.image}
onChange={handleInputChange}
/>
</div>
<div>
<label>Cuisine:</label>
<select
name="cuisine_id"
value={selectedCuisine}
onChange={handleCuisineChange}
required
>
<option value="">Select cuisine...</option>
{cuisines.map(cuisine => (
<option key={cuisine.id} value={cuisine.id}>{cuisine.name}</option>
))}
{/* Prevents duplicating of cuisines */}
{!cuisines.some(cuisine => cuisine.name === 'Other') && (
<option value="Other">Other</option>
)}
</select>
<input
id="other-cuisine-input"
type="text"
placeholder="Enter custom cuisine name"
value={otherCuisineName}
onChange={handleOtherCuisineNameChange}
style={{ display: selectedCuisine === 'Other' ? 'block' : 'none' }}
/>
</div>
<button className="button" type="submit">Add Recipe</button>
</div>
</form>
</div>
);
}
export default AddRecipe;
2
Answers
You should use npm dropdown library: Library
Get data in a list and then just pass it to dropdown
You are using
display: none
to show and hide your html and this is not a correact approach in React. The correct approach is using condional rendering – see: https://react.dev/learn/conditional-renderingSo in you case you should remove direct HTML manipulation from
Then in your JSX
The snippet above uses logical AND operator. More on this approach here: https://react.dev/learn/conditional-rendering#logical-and-operator-