The problem is I have two redux stores
items(Items Store
quotationItems(Quote Items.
When a product item is added to quotationItems I Would to show <RedButton title="Remove" /> or when the quotationItems is empty the <AddButton title="Add" /> should be shown.
using if statement tends to re-render the component and adds new components e.g: After adding a new product to quotation items, there will be a new <AddButton /> in FlatList Component.
interface IProps {
items: ItemInterface[];
documentItems: ItemInterface[];
onAddItem: any;
}
const ItemFlatList2: FC<Partial<IProps>> = ({
items,
documentItems,
onAddItem,
}) => {
const TestView = (itemCode) => {
documentItems.map((x) => {});
};
return (
<FlatList
data={items}
keyExtractor={(item) => item.itemCode.toString()}
renderItem={({
item: { itemCode, itemDescription, itemSellingPrice },
}) => {
return (
<div className={styles.itemContainer}>
<h4>Item Code: {itemCode}</h4>
<h4>Description: {itemDescription}</h4>
<div>
{documentItems.map((x) => {
x.itemCode === itemCode ? (
<RedButton title={"Remove"} key={itemCode} />
) : (
<AddButton title={"Add"} key={itemCode} />
);
})}
</div>
</div>
);
}}
/>
);
};
Other options I've tried:
I've also tried this, still doesn't work, the buttons will show up but after clicking on the first button, which will successful add the product item to quotation item store but when I try and click on the 2nd or 3rd button of `<AddButton title={'Add'} key={itemCode} /> I get no response.
<div>
{documentItems.length <= 0 ? (
<AddButton
title={"Add"}
key={itemCode}
onClick={() => onAddItem(itemCode)}
/>
) : (
documentItems!.map((x) =>
x.itemCode === itemCode ? (
<RedButton title={"Remove"} key={itemCode} />
) : (
<
AddButton title={"Add"} key={itemCode} onClick={() => onAddItem(itemCode)} />
)
)
)}
</div>
This is the result of the modified code above:
Please add the return keyword.
documentItems.map((x) => {
return (x.itemCode === itemCode ? (
<RedButton title={"Remove"} key={itemCode} />
) : (
<AddButton title={"Add"} key={itemCode} />
);
)})
Or Just remove the curly braces.
documentItems.map((x) => (x.itemCode === itemCode ? (
<RedButton title={"Remove"} key={itemCode} />
) : (
<AddButton title={"Add"} key={itemCode} />
)))
Based on the updations that you did in the questions. It is an issue with the data in "documentItems". Since you only need 1 button per item code. Instead of map use find. It will return 1 item and fix this duplicacy.
Related
I have an onClick in map function, if I click onClick it will change state of all map item not that item which I clicked. I am using useState hook.
const [open, setOpen] = useState(true);
{
FilterAvailable.map((item, id) => {
return (
<li className="filterItem">
<div
className="filterBtn flex align-center justify-between"
onClick={() => setOpen(!open)}
>
<h2>{item.catogery}</h2>
<div>
{open ? (
<IoIosArrowDown className="downArrow" />
) : (
<IoIosArrowUp className="downArrow" />
)}
</div>
</div>
{item.options.map(option => {
return (
<>
{open && (
<ul className="filterOption">
<li className="filterOptionitem">
<button>{option}</button>
</li>
</ul>
)}
{/* <div className="hrLine"></div> */}
</>
);
})}
</li>
);
});
}
I want to open only those item option which click.
Your state is in the wrong place, you need to break the component and have a open state per filterableItem
const Filters = () => {
return FilterAvailable.map((item, id) => {
return <FilterItem item={item} />;
});
};
const FilterItem = ({ item }) => {
const [open, setOpen] = useState(true);
return (
<li className="filterItem">
<div
className="filterBtn flex align-center justify-between"
onClick={() => setOpen(!open)}
>
<h2>{item.catogery}</h2>
<div>
{open ? (
<IoIosArrowDown className="downArrow" />
) : (
<IoIosArrowUp className="downArrow" />
)}
</div>
</div>
{item.options.map(option => {
return (
<>
{open && (
<ul className="filterOption">
<li className="filterOptionitem">
<button>{option}</button>
</li>
</ul>
)}
</>
);
})}
</li>
);
};
Put the index inside state on onclick , inside map check if state index equals to map index and you are done
Consider moving the mapped elements to their own component with props - then you create and set your open and closed state there.
I have implemented a simple drag and drop code here below using react-beautiful-dnd. The frontend alone works perfectly fine, however, when I tried to connect this with the backend the items in the droppable context are unable to be dragged. That is, I am unable to drag the items within the column and also between columns. Further, I am unable to figure out how to pass the index of the elements in the mongoDb database.
The code I used is here below
projectsDashboard.js
function ProjectsDashboard() {
const handleDragEnd = ({destination, source}) => {
if (!destination) {
return
}
if (destination.index === source.index && destination.droppableId === source.droppableId) {
return
}
// Creating a copy of item before removing it from state
const itemCopy = {...state[source.droppableId].items[source.index]}
setState(prev => {
prev = {...prev}
// Remove from previous items array
prev[source.droppableId].items.splice(source.index, 1)
// Adding to new items array location
prev[destination.droppableId].items.splice(destination.index, 0, itemCopy)
return prev
})
}
const dispatch = useDispatch();
useEffect(() => {
dispatch(getStages());
},[dispatch]);
const { stage } = useSelector(state => state.stage);
var formattedArray = stage.map(item => Object.keys(item).map(i => item[i]));
console.log(formattedArray)
return (
<DragDropContext onDragEnd={handleDragEnd}>
{_.map(state, (data, key) => {
return(
<div key={key} className={"column"}>
{console.log(key , "KEY")}
<ProjectWrapper className="border">
<h3 className="title">{data.title}</h3>
</ProjectWrapper>
<Droppable droppableId={key}>
{(provided, snapshot) => {
return(
<div>
<div
ref={provided.innerRef}
{...provided.droppableProps}
className={"droppable-col"}
>
<hr className="line" style={{opacity: 10 }}></hr>
{stage.map(stages=>{
if(stages.status == key)
return(
<Draggable key={stages._id}
//index={index}
draggableId={stages._id} className="drag">
{(provided, snapshot) => {
console.log(snapshot)
return(
<div
className={`item ${snapshot.isDragging && "dragging"}`}
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
>
{/* card name */}
<button className="stageDetails" style={{padding: "0",border: "none", background: "none"}}>
{stages.stageName}
</button>
<DeleteOutlinedIcon className="delete" />
</div>
)
}}
</Draggable>
)
})}
{provided.placeholder}
</div>
</div>
)
}}
</Droppable>
</div>
)
})}
</DragDropContext>
</div>
);
};
export default ProjectsDashboard;
I am trying to change a specific item of an object , which is contained by an array of objects, yet I cannot seem to find my mistake:
This is my formset array which contains the objects :
const [formset,setFormset]=React.useState([
{
id: uuidv4(),
product:"",
price: 0,
quantity: 0,
productSubtotal: 0,
}
])
And this is how I am trying to change the product , for example:
const handleProduct = (e,id) => {
setFormset(
formset.map(item=>
(item.id !== id? item :
{
...item , product: e.target.value
})
)
)
}
EDIT: The return statement from the parent component:
return (
<div>
{formset.map((item)=>{
return(
<PieChartGroupFormPresenter
item={item}
key={item.id}
id={item.id}
handleProduct={handleProduct}
handleQuantity={handleQuantity}
purchaseList={purchaseList}
product={item.product}
quantity={item.quantity}/>
)
}
)
}
<button type="button" onClick={handleClick}>More</button>
</div>
)
The presenter component :
const PieChartGroupFormPresenter=({handleProduct,handleQuantity,product,quantity,item,purchaseList,id})=>{
return (
<div>
<FormControl>
<Select onChange={(id)=>handleProduct(id)} value={product}>
{Object.keys(purchaseList).map((item,index) =>
<MenuItem value={item} key={index}>{item}</MenuItem>
)}
</Select>
<TextField onChange={(id)=>handleQuantity(id)} value={quantity} />
<TextField value={item.price} disabled>{item.price}</TextField>
</FormControl>
</div>
)
}
I have tried multiple variations of this approach yet none of them seem to work. Thank you very much!
You passing event as id, should be
onChange={(event)=>handleProduct(event, id)}
Same mistake for other field
//<TextField onChange={(id)=>handleQuantity(id)} value={quantity} />
<TextField onChange={(event)=>handleQuantity(event, id)} value={quantity} />
const handleProduct = (e) => {
setFormset({...formset,product: e.target.value})
}
I have a component that renders some data coming from an array. I need to filter that array depending on a condition. I don't know if filter the array is the proper way, or just to remove the item I don't need from that array.
The component looks like this:
const PassengerCardBasedOnRoute = ({
passengerCardId,
isAddToMyPassengersSuccess,
unassignedDropOffPassengers
}) => {
const filteredData = filterByParam =>
filterByParam.filter(obj =>
Object.keys(obj).some(key =>
String(obj[key])
.toLowerCase()
.includes(searchParam.toLowerCase()),
),
);
const componentToRenderBasedOnParams = info => (
<View key={info.id}>
{isAddToMyPassengersSuccess && info.id === passengerCardId && (
<PassengersAdded name={info.name} id={info.id} />
)}
<PassengersInfo
id={info.id}
name={info.name}
/>
</View>
);
const showFeedbackIfNoLength = data => {
if (size(filteredData(data))) {
filteredData(data).map(info => componentToRenderBasedOnParams(info));
}
};
return (
<>
<OptionsModal>{<AllPassengersOptionsModal />}</OptionsModal>
<View>
{unassignedDropOffPassengers && showFeedbackIfNoLength(unassignedDropOffPassengers)}
</View>
</>
);
};
The array of data I am attempting to work on is this unassignedDropOffPassengers. Which you may see above.
And the key function to work on is this:
const componentToRenderBasedOnParams = info => (
<View key={info.id}>
{isAddToMyPassengersSuccess && info.id === passengerCardId && (
<PassengersAdded name={info.name} id={info.id} />
)}
<PassengersInfo
id={info.id}
name={info.name}
/>
</View>
);
The valid condition is this:
{isAddToMyPassengersSuccess && info.id === passengerCardId && (
<PassengersAdded name={info.name} id={info.id} />
)}
What I should should do is that when the condition above is met, I should remove the item from unassignedDropOffPassengers. Or just filter it like here where I am applying a filter:
const filteredData = filterByParam =>
filterByParam.filter(obj =>
Object.keys(obj).some(key =>
String(obj[key])
.toLowerCase()
.includes(searchParam.toLowerCase()),
),
);
What I want to know is how to achieve it/adapt it with my code. Based on the condition I mentioned above isAddToMyPassengersSuccess && info.id === passengerCardId.
The item in the array that I need to omit, is the one matching passengerCardId.
So any ideas?
EDIT:
I am using lodash btw.
I'm trying to display a flatlist with a header component, but can't seem to remove the first and last separators.
This is how I'm currently rendering the items.
renderSeparator = () => (
<Separator
marginTop="$unitOne"
marginBottom="$unitOne"
/>
)
render() {
const { newsData } = this.props;
return (
<Container>
{newsData.length > 0
? (
<FlatList
data={newsData}
renderItem={({ item }) => (
item.featured === null && this.renderNews(item)
)}
keyExtractor={item => item.id.toString()}
style={styles.container}
ItemSeparatorComponent={this.renderSeparator}
ListHeaderComponent={this.renderFeaturedNews}
/>
)
: <Placeholder />
}
</Container>
);
}
Any help is much appreciated. Thanks!
I think that will work for you;
<FlatList
data={newsData}
renderItem={({ item, index }) => (
item.featured === null && this.renderNews(item)
)}
keyExtractor={item => item.id.toString()}
style={styles.container}
ItemSeparatorComponent={(index===0 || index === newsData.length - 1) ? null : this.renderSeparator}
ListHeaderComponent={this.renderFeaturedNews}
/>
Don't know what was the situation with FlatList when this question was asked but right now ItemSeparatorComponenet won't be generated for last and first.
Rendered in between each item, but not at the top or bottom
Read more here