I am changing the state with onClick and adding a border to the data of that state name. But when I click the other boxes, the previously added border is not removing. Here is my code;
const [toggleState, setToggleState] = useState(null);
return (
<React.Fragment>
<Col sm="6">
<Card className="text-center">
<CardBody onClick={() => setToggleState(user.name)} className={toggleState === user.name ? 'selectedItem' : '' + ' cursorPointer'} >
<Row onClick={event => props.onChange('true')}>
<Col sm="4">
</Col>
</Row>
</CardBody>
</Card
</Col>
</React.Fragment>
Hard to say what the className you're looking to set is, but Unmitigated seems to have a good idea about that issue. I also noticed that you don't close your
</Card
correctly on the third row from the bottom, this might affect how the page behaves as well.
Related
Here is the jsx
When i click the ROW myParentClick is triggered but when i click on any child which is myChildClick myChildClick2
Then it triggers both the parent and child.
The Parent is triggered first and then the child
{myData?.map((item, index) => {
return(
<Row onClick={() => myParentClick(index)}>
<Col>
// some html tags
</Col>
<Col>
// some html tags
</Col>
<Col>
// React Bootstrap DropDown
<DropDown>
<DropDown.Toggle>
// code
</DropDown.Toggle>
<DropDown.Menu>
<DropDown.Item onClick={() => myChildClick(index)}>
<p>some TEXT</p>
</DropDown.Item>
</DropDown.Menu>
</DropDown>
</Col>
<Col onClick={() => myChildClick2(index)} >
<p>some TEXT</p>
</Col>
<Col onClick={() => myChildClick3(index)} >
<p>some TEXT</p>
</Col>
</Row>
)
})}
I have tried, on child click e.stopPropagation(); which is not working
onClick={
(e) => {
e.stopPropagation();
myChildClick(index)
}
}
How to Prevent Parent onClick when clicked on child onClick ?
Try
onClick={
(e) => {
if (e.defaultPrevented) return
e.preventDefault()
myChildClick(index)
}
}
i took your code and tried to reproduce your issue. for some reason your stopPropagation doesnt work for you, but when i tried it, it works fine:
https://stackblitz.com/edit/react-ts-mk1dcr
I've implemented react beautiful dnd into my app, however I've found that dragging items that are initialised in the first column mostly doesn't work (it sometimes works if you keep refreshing). I tried swapping my columns around and it appears the first one rendered has the problem rather than one column having an issue.
I'm not sure what is causing it, the error I receive in the console from the library is:
Unable to find draggable with id: 6112804b8127dd10b00138d8.
The id however matches the ids in my lists and the HTML viewed in inspect element.
Here's the minimum code, I've not included the functions for filtering search, reordering, move and onDragEnd (isn't being fired as it doesn't find the draggable)
const id2List = {
'available': availableSections,
'selected': selectedSections
};
const getList = id => id2List[id];
return (
<Container>
<Widget title={template.name} paddingStyle="10px" buttonRight={<SaveButton handleSubmit={handleSubmit} loading={loading}/>}>
<DragDropContext onDragEnd={onDragEnd}>
<Row>
<Col >
Available Sections
<Form.Control onChange={(e) => setSearchTextAvailable(e.target.value)} className="mb-3" type="text" placeholder="Search..." />
<Droppable key="available" droppableId="available">
{provided => (
<div ref={provided.innerRef} {...provided.droppableProps}>
{Object.keys(visibleAvailableSections).map((section) => {return <SectionCard key ={visibleAvailableSections[section]._id} section={ visibleAvailableSections[section] } index={parseInt(availableSections.indexOf(visibleAvailableSections[section])) } /> })}
{provided.placeholder}
</div>
)}
</Droppable>
</Col>
<Col>
Selected Sections
<Form.Control onChange={(e) => setSearchTextSelected(e.target.value)} className="mb-3" type="text" placeholder="Search..." />
<Droppable key="selected" droppableId="selected">
{provided => (
<div ref={provided.innerRef} {...provided.droppableProps}>
{Object.keys(visibleSelectedSections).map((section) => {return <SectionCard key ={visibleSelectedSections[section]._id.toString()} section={ visibleSelectedSections[section] } index={parseInt(selectedSections.indexOf(visibleSelectedSections[section])) } /> })}
{provided.placeholder}
</div>
)}
</Droppable>
</Col>
</Row>
</DragDropContext>
</Widget>
</Container>
)
const SectionCard = ({section, index}) => {
return (
<Draggable draggableId={section._id.toString()} key={section._id} index={index}>
{provided => (
<Card key={"card-" + section._id.toString()} style={{ width: '18rem' }}
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
>
<Card.Body>
<Card.Title>{ section.name }</Card.Title>
<Card.Subtitle className="text-muted">{ section.description }</Card.Subtitle>
{ section.tags.map((tag) => {
return <Badge pill bg={"secondary"} key={section._id + tag} >{ tag }</Badge>
})}
</Card.Body>
</Card>
)}
</Draggable>
);
}
I want to build a simple component where the data comes from a JSON list. On the website I can see the console.log(dat.CardId) so it works for just console.log(). I can't see the cards from the .map function. The Style is bootstrap. I really don't think that something is wrong at the code.
import { Card,Button,Container,Row,Col } from 'react-bootstrap'
const data = [{'CardTitle':'Simple Website','CardText':"Some quick example text to build on the card title and make up the bulk of the card's content.", "CardId":"Simple-Website"},{'CardTitle':'Simple Website','CardText':"Some quick example text to build on the card title and make up the bulk of the card's content.", "CardId":"Simple-Website"} ]
export default function Cards() {
return (
<>
<div>
<Container fluid>
Cards
{data.map(dat => {
{console.log(dat.CardId)}
<Row>
<Col>
<Card style={{ width: '18rem' }}>
<Card.Img variant="top" src="pexels-tima-miroshnichenko-6612358 (2).jpg/100px180" />
<Card.Body>
<Card.Title>{dat.CardTitle}</Card.Title>
<Card.Text>
{dat.CardText}
</Card.Text>
<Button variant="primary">Go somewhere</Button>
</Card.Body>
</Card>
</Col>
</Row>
})}
</Container>
</div>
</>
)
}
Use return ( ... ) in a .map to render an element. https://stackoverflow.com/a/39999745/15257712
Example:
array.map((entry, index) => {
return (
<div key={index}>
...
</div>
)
})
I'm working on a recipe app and I'm having some issues rendering my ingredient list from a Firebase array. I'm new to JS and React, so i apologize if this is something simple. I really appreciate any help that's provided! I've attached my code and an example of how the array is currently being rendered. I've also included a screenshot of the Firebase data structure. [firebaseStructure][1]
useEffect(() =>{
database.collection('recipes').onSnapshot(snapshot => {
setRecipeCard(snapshot.docs.map(doc => ({id:doc.id, recipes:doc.data()})));
console.log(snapshot.docs.map(doc => ({id:doc.id, recipes:doc.data()})))
})
}, []);
useEffect(() =>{
database.collection('recipes').onSnapshot(snapshot =>{
setIngredientsList(snapshot.docs.map(doc =>({id:doc.id, ingredient: doc.data().ingredients1})));
console.log(snapshot.docs.map(doc =>({id:doc.id, ingredient: doc.data().ingredients1})))
})
}, []);
return (
<div>
<Container>
<Row>
{recipeCard.map(recipes =>(
<Col md={4} key={recipes.id}>
<Card style={{ width: '100%' }}>
<Card.Img variant="top" src={recipes.recipes.url} style={{height:'300px',width:'100%'}} />
<Card.Body>
<Card.Title>{recipes.recipes.title}</Card.Title>
{/**<Card.Text> **/}
<ul key={recipes.id}>
{ingredientsList.map(recipes =>(
<li key={recipes.id}>
{recipes.ingredient}
</li>
))}
</ul>
{/** </Card.Text> **/}
<Button variant="secondary">Head to Recipe</Button>
</Card.Body>
</Card>
</Col>
))}
</Row>
</Container>
</div>
)
}
[current rendered output][2]
[1]: https://i.stack.imgur.com/bFBdr.png
[2]: https://i.stack.imgur.com/xU1fC.png
I think a lot of the confusion here has come from the naming convention, and the attempt to use separate state for the recipieCard and ingredientsList. You've ended up rendering all the ingredients for all recipies instead of just the one's relevant to that recipie. If you ever find yourself accessing properties like recipies.recipies, you know you need to do some refactoring (if you have complete control of the project).
First things first, you only need one useEffect to access your database and process the data. It all belongs together, so there's no need to separate it into separate states. Notice how I've renamed the state as recipieCards plural. This is an array or list of data objects, so it should have a pluralised name. Each data object now has the property data instead of recipies, which more accurately describes what it contains (i.e. the data for ONE recipie).
useEffect(() =>{
database.collection('recipes').onSnapshot(snapshot => {
setRecipeCards(snapshot.docs.map(doc => ({id:doc.id, data:doc.data()})));
console.log(snapshot.docs.map(doc => ({id:doc.id, data:doc.data()})))
})
}, []);
Now in the return fuction it becomes much more clear what's going on. We take the array of recipieCards and map over it to access each recipie data object one at a time. For each data object use the id as its key, and take the url and title from data. Now you can access that recipie's ingredients directly from the same data object, under the property data.ingredients1.
return (
<div>
<Container>
<Row>
{recipeCards.map(recipe =>(
<Col md={4} key={recipe.id}>
<Card style={{ width: '100%' }}>
<Card.Img variant="top" src={recipe.data.url} style={{height:'300px',width:'100%'}} />
<Card.Body>
<Card.Title>{recipe.data.title}</Card.Title>
{/**<Card.Text> **/}
<ul>
{recipie.data.ingredients1.map(ingredient =>(
<li key={ingredient}>
{ingredient}
</li>
))}
</ul>
{/** </Card.Text> **/}
<Button variant="secondary">Head to Recipe</Button>
</Card.Body>
</Card>
</Col>
))}
</Row>
</Container>
</div>
);
You don't need to call the DB twice in two separate useEffect to do what you want. You should only call the DB once for efficiency in this case.
Also, you're re declaring recipes within the second map, this could cause errors, you should avoid using the same variable name for different variables. Your problem may be related to this. I edited the following code assuming you only use the first useEffect with setRecipeCard.
{recipeCard.map(recipe =>(
<Col md={4} key={recipe.id}>
<Card style={{ width: '100%' }}>
<Card.Img variant="top" src={recipe.recipes.url} style={{height:'300px',width:'100%'}} />
<Card.Body>
<Card.Title>{recipe.recipes.title}</Card.Title>
{/**<Card.Text> **/}
<ul key={recipe.id}>
{recipe.ingredients1.map(ingredient =>(
<li key={recipes.id}>
{ingredient}
</li>
))}
</ul>
{/** </Card.Text> **/}
<Button variant="secondary">Head to Recipe</Button>
</Card.Body>
</Card>
</Col>
))}
Can you try out this code? Please let us know specifically if you are getting any errors :)
It is a bit hard to explain what it is exactly I am trying to do, but it should be pretty obvious by looking at the code.
Here is the full code for the react component, take note that the endpoint that populates the prop is missing as it hasnt been developed yet.
import React, { useState } from 'react';
import { Modal, ModalHeader, ModalBody, Button, Row, Col, Container } from 'reactstrap'
import '../../scss/hitchpin/star-rating.scss'
const ReviewModal = (props: Props) => {
const {
offering,
ratings,
comments,
response,
} = props
const [modal, setModal] = useState(false);
const [sellerReviews, setSellerReviews] = useState(false);
const toggle = () => {
setModal(!modal);
if (document.getElementById('seller').onclick) {
setSellerReviews(!sellerReviews);
}
}
return (
<div>
<Button id="seller" className="btn-sm ml-2 btn btn-secondary" onClick={toggle}> Seller Review Details </Button>
<Button className="btn-sm ml-2 btn btn-secondary" onClick={toggle}> Buyer Review Details </Button>
<Modal isOpen={modal} toggle={toggle}>
<ModalHeader toggle={toggle}>Review Details</ModalHeader>
<ModalBody>
<div>
<Container>
<Row>
<Col>As a Seller</Col>
</Row>
</Container>
</div>
<div className="p-3">
<h3>{offering.title}</h3>
<p>Category: {offering.category}</p>
<Container>
<Row>
<Col xs="6">Overall</Col>
<Col xs="6" class="Stars" style={'--ratings:' ratings.overall}></Col>
</Row>
<Row>
<Col xs="6">Response Time</Col>
<Col xs="6" class="Stars" style={--ratings: ratings.response}></Col>
</Row>
<Row>
<Col xs="6">Friendliness</Col>
<Col xs="6" class="Stars" style={--ratings: ratings.friendliness}></Col>
</Row>
<Row>
<Col xs="6">Punctuality</Col>
<Col xs="6" class="Stars" style={--ratings: ratings.punctuality}></Col>
</Row>
{sellerReviews && (
<Row>
<Col xs="6">Quality of Product/Service</Col>
<Col xs="6" class="Stars" style={--ratings: ratings.quality}></Col>
</Row>
)}
</Container>
<div>
<p>{!sellerReviews ? "Buyer's Comments:" : "Seller's Comments"}</p>
<textarea readOnly>
{comments.message && (
{comments.message}
)}
</textarea>
</div>
<div>
<p>{sellerReviews ? "Buyer's Response:" : "Seller's Response"}</p>
<textarea readOnly>
response.message && (
{response.message}
)}
</textarea>
</div>
</div>
</ModalBody>
</Modal>
</div>
);
}
export default ReviewModal
The issue I am having is, in the <Col> tags with the style attribute, I need to pass the prop ratings.category to the --ratings css variable. I know that if the number was static I could easily pass --ratings: 2.5, which is how i tested the code. However, in implementation, the floating point number will be variable and changing. Hence the issue.
First of all, I believe that
<Col xs="6" class="Stars" style={'--ratings:' ratings.overall}></Col>
should be
<Col xs="6" class="Stars" style={{'--ratings': ratings.overall}}></Col> (notice extra braces)
Also, if values are numeric, React might add 'px'. You might want to convert to string:
<Col xs="6" class="Stars" style={{'--ratings': String(ratings.overall)}}></Col>
UPD
Here is an example with latest React version (old versions do not support css variables via style prop): https://codesandbox.io/s/shy-star-mxu74