Re-ordering JSX including React's Context Provider - javascript

I'm wondering if there is a way of re-factoring this code so that RepeatableAttributeSetContextProvider does not wrap all of the JSX elements but sits above them (so opens and closes before StyledHorizontalAttributesTable). When I do that at present, then values like enteredObject: "cannot be defined".
I want to try this so that I can decouple of some of the JSX that comes along with RepeatableAttributeSetContextProvider (such as labels) away from the rest of my JSX (to sit on top instead of wrap) Any ideas would be great!
return (
<div className={className}>
{objects.map((enteredObject, index) => (
<RepeatableAttributeSetContextProvider
form={form}
object={enteredObject}
key={`${enteredObject.key}-${enteredObject.repeatIndex}`}
>
<StyledHorizontalAttributesTable className="attributeset-row">
{enteredObject.attributeCollection.questions
.filter(filterRepeatAttributes)
.map((attribute) => (
<Fragment key={attribute.key}>
{renderAttribute(enteredObject, attribute, formLayout)}
</Fragment>
))}
<StyledButton
className="remove-btn"
type="link"
buttonStyle="LINK"
name="delete"
dataId={`delete-${enteredObject.key}-${index}`}
icon="bin"
onClick={() => onRemove(enteredObject)}
>
<Message id="Form.Button.Remove" defaultMessage="Remove" />
</StyledButton>
</StyledHorizontalAttributesTable>
</RepeatableAttributeSetContextProvider>
))}
</div>
);

Do you mean something like
return (
<div className={className}>
{objects.map((enteredObject, index) => (
<>
<RepeatableAttributeSetContextProvider
form={form}
object={enteredObject}
key={`${enteredObject.key}-${enteredObject.repeatIndex}`}
/>
<StyledHorizontalAttributesTable className="attributeset-row">
{enteredObject.attributeCollection.questions
.filter(filterRepeatAttributes)
.map((attribute) => (
<Fragment key={attribute.key}>
{renderAttribute(enteredObject, attribute, formLayout)}
</Fragment>
))}
<StyledButton
className="remove-btn"
type="link"
buttonStyle="LINK"
name="delete"
dataId={`delete-${enteredObject.key}-${index}`}
icon="bin"
onClick={() => onRemove(enteredObject)}
>
<Message id="Form.Button.Remove" defaultMessage="Remove" />
</StyledButton>
</StyledHorizontalAttributesTable>
</>
))}
</div>
);
But then you obviously won't have any access to the (assumed) context provided by RepeatableAttributeSetContextProvider. If you do need it, then you do need to wrap your JSX within it. If you don't need it, then why have the component at all?

Related

React - I'm using the onclick option which requires a variable from a component that dynamically renders a series of elements, but it doesn't work

dropdownClick =(value ) => {
this.setState({searchGroup: value.name, elementSelected: value})
}
( I tried inserting the setState block inside the onClick and it do not worck too )
<InputGroup className="mb-2">
<Input value={this.state.searchGroup} onChange={(e) => this.filtergroups(e.target.value)} />
<InputGroupButtonDropdown addonType="append" isOpen={this.state.drop} toggle={this.AbrirCerrarDropdown} >
<DropdownToggle caret className="red button">Grupos</DropdownToggle>
<DropdownMenu>{this.state.skillGroupsFiltered.map((element, index) => (
<DropdownItem key={index} onClick={() => this.dropdownClick(element)}>{element.name}</DropdownItem>
))}
</DropdownMenu>
</InputGroup>

React beautiful dnd first column of two not working properly - unable to find draggable with id

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

passing props in React with a map function

I know how to pass basic props in React but I am a bit stumped on this one. Rather than try to explain all of it in this paragraph I think showing will do better justice to the problem.
Here is how it was before trying to break it off into its own separate component.
{ <div className="flex-item-main">
<ol>
{this.state.thoughts.map((thought, index)=>
<DisplayPoem className='displayPoem' key={index} onClick={() => { this.handleDeleteClick(index) }} name='Delete Thoughts' value={thought} />
)}
</ol>
</div> }
Here is how it will look as its own separate component taking props from the parent:
{ <div className="flex-item-main">
<ol>
{this.props.thoughtsProp.map((thought, index)=>
<DisplayPoem className='displayPoem' key={index} onClick={this.props.onClick} name={this.props.name} value={thought} />
)}
</ol>
</div> }
Here is the parent component passing down the props: I have no idea what to do with onClick={() => { this.handleDeleteClick(index) }} as I need index from the .map() function in the component. I hope any of this made sense and I am happy to add updates, im not sure how to explain the problem which is probably why im having trouble solving it. Still new to React.
<DisplayPoemList thoughtsProp={this.state.thoughts} onClick={() => { this.handleDeleteClick(index) }} name='Delete Thoughts' />
You could remove the arrow function from props and pass you method as a prop.
Change this code (look at the onClick):
<DisplayPoemList thoughtsProp={this.state.thoughts} onClick={() => { this.handleDeleteClick(index) }} name='Delete Thoughts' />
To this code:
<DisplayPoemList thoughtsProp={this.state.thoughts} onClick={this.handleDeleteClick } name='Delete Thoughts' />
Then your DisplayPoemList will get a function onClick that expecting for index when it called.
Use an arrow function to create an instance of the function with an index in a scope for each element.
{ <div className="flex-item-main">
<ol>
{this.props.thoughtsProp.map((thought, index)=>
<DisplayPoem className='displayPoem' key={index} onClick={() => this.props.onClick(index)} name={this.props.name} value={thought} />
)}
</ol>
</div> }

Modal not selecting current object

I have this class in React:
render() {
let addedItems = this.props.items.length ? (
this.props.items.map(item => {
return (
<li className="collection-item avatar" key={item.id}>
<div className="item-desc">
<Modal trigger={<Button onClick={this.handleOpen}>Editar</Button>}>
<Header icon="archive" content="Archive Old Messages" />
<Modal.Content>
{/* CHEESE */}
<Button.Group>
<Link to="/cart">
<Button
icon="plus"
onClick={() => {
console.log("BUT +");
this.handleCheese(item, "+");
}}
/>
</Link>
<Button content="Cheese" labelPosition="left" />
<Link to="/cart">
<Button
icon="minus"
onClick={() => {
this.handleCheese(item, "-");
}}
/>
</Link>
<h2>{item.queijo}</h2>
</Button.Group>
</Modal.Content>
</Modal>
</div>
</li>
);
})
)
}
In resume a modal should open according to the object I'm selecting.
But in my code the item.id is selecting the last object I inserted in the addedItems.
I need the modal to have the info about the obj I selected.
In case you want to see all code is in: https://github.com/fernanda-avelar/burguer_cart ->
This page is the /src/components/Cart.js
I guess you can have only one modal in your window, that's why it's taking the last one (by having overriden all others).
So instead you should put your modal out of the .map.
Also, keep track of the selected item via a controlled state selectedItem.
Then use it the the Modal.Content :
render() {
return (
<>
<Modal.Content>
/* content depending of this.state.selectedItem */
</Model.Content>
/* your other stuff */
</>
)
}

Click events are not available on the map of the react

{userList.map(v => (
<Card
key={v.user}
onClick={() =>
console.log("object")
}
>
<Card.Header
title={v.user}
thumb={require(`../img/${v[tableName].avatar}.png`)}
extra={<span>{v[tableName][extra]}</span>}
/>
<Card.Body>
{v[tableName].desc.split(/\n/g).map((v, k) => (
<li key={k}>{v}</li>
))}
</Card.Body>
</Card>
))}
Click events are not available on the .map() function in React
Card Component of React material UI does not support onClick props so you should not use it.
Quick Fix would be to enclose it inside a div and add onClick on the div as shown below:
<div onClick=> {() =>
console.log("object")
}>
<Card>
.....
</Card>
</div>
Or You can use some different library from :
https://material-ui.com/api/card-action-area/

Categories