When selecting item from an array renders all items react js - javascript

I have the following problem, when selecting an item through a checkbox and pressing a button so that that selected item is added to my new array, all the items are added.
I use the function map and return the component with their respective key and item:
renderFiltersInlcuye() {
if(this.props.incluye){
return this.props.incluye.map((item, index) =>{
return <BusquedaPaquetesFiltrosAplicadosItems
key = {item.value}
item= {item}
onClickClose={this.removeItemIncluye.bind(this,index)}
/>
})
}
}
And in my other component I render the following:
render () {
return(
<ul>
<li>
<span className="badge badge-info " >
<button onClick={this.props.onClickClose} type="button" className="close" ><i className="fas fa-times-circle"></i> </button>
{this.props.item.texto}
</span>
</li>
</ul>
);
}

Related

How to create a recursive components with add edit and delete function in react js?

I just want to create a category list with each one having a sub-category. and it should be added, edit and delete
As an example
- Breakfast > Egg Types > Some of name
- Lunch > Chicken > Some of name
I had experience with a similar case. Only I had comments
I should you to create a Component which the take as props array with items. I recommend taking the following structure of menu item
{
id:1,
text:"All",
subItems:[{
id:67,
text:"Sub",
subItems:[{
id:98,
text:"Sub of Sub"
}]
}]
}
This is my final answer
import {useState} from "react";
const Menu=({propsItems}:{propsItems})=>{
const [items,setItems]=useState(propsItems);
const deleteItemHandle=(id)=>{
setItems(prevState =>prevState.filter(item=>item.id!==id) )
}
const [inputValue,setInputValue]=useState("")
const [editValue,setEditValue]=useState("")
const [isEditMode,setIsEditMode]=useState(false);
const addItemHandle=()=>{
if (inputValue.trim()){
setItems(prevState =>[...prevState,{id:Math.random(),text:inputValue,subItems:[]}] )
setInputValue("")
}
}
const editItemHandle=(id:number)=>{
if (editValue){
setItems(prevState =>prevState.map(item=>{
if (item.id===id){
return {...item,text:editValue}
}
return item
}) )
setIsEditMode(false)
setEditValue("")
}
}
const toggleEditMode=()=>setIsEditMode(true)
return (
<div>
<ul>
{items.map(item=>{
return <li key={item.id}>
<span>
{isEditMode ? <div>
<input onChange={(e:any)=>setEditValue(e.target.value)} value={editValue} type="text"/>
<button onClick={()=>editItemHandle(item.id)} >Edit</button>
</div>: <span onDoubleClick={toggleEditMode}>
{item.text}
</span>}
<span onClick={()=>deleteItemHandle(item.id)}
style={{color:"red"}}>X
</span>
{item.subItems?.length ? <Menu propsItems={item.subItems}/>:"" }
{!item.subItems.length && <div>
<input value={inputValue} onChange={(e)=>setInputValue(e.target.value)}
type="text" placeholder={"Add item"}/>
<button onClick={addItemHandle}>Add Item</button>
</div> }
</span>
</li>
})}
</ul>
<div>
<input value={inputValue} onChange={(e)=>setInputValue(e.target.value)}
type="text" placeholder={"Add item"}/>
<button onClick={addItemHandle}>Add Item</button>
</div>
</div>
)
}
export default Menu

Removing li items with Button onClick

I'm trying to add an active "x" button to each li so that a user can click on it to remove the li from the list. I've added the button so that it appears with each list item, but I don't know what I would need to enter onClick to remove the corresponding li after clicking. Any suggestions?
<div>
<h5 className="col-lg-4 mt-4">Selected Files</h5>
<ul className="nobull text-sm">
{files.map((file) => (
<li key={file.path}>
<Button className="ml-3" close />
{file.path} - {(file.size / 1024).toFixed(1)} KB
</li>
))}
</ul>
</div>
In case it helps anyone, after further research, I was able to get my answer. I created the following const:
const remove = file => {
const newFiles = [...files]; // make a var for the new array
newFiles.splice(file, 1); // remove the file from the array
setFiles(newFiles); // update the state
};
Then I updated my code as such:
<div>
<h5 className="col-lg-4 mt-4">Selected Files</h5>
<ul className="nobull text-sm">
{files.map((file, i) => (
<li key={file.path} className="py-2">
<Button className="ml-3" onClick={() => remove(i)} close />
{file.path} - {(file.size / 1024).toFixed(1)} KB
</li>
))}
</ul>
</div>;
You can try something like this:
const handleDelete = (index) => {
let filesArr = [...files];
filesArr.splice(index, 1); // This will delete the element
// Update the state with this modified array
setFiles(filesArr); // like this
}
<div>
<h5 className="col-lg-4 mt-4">Selected Files</h5>
<ul className="nobull text-sm">
{files.map((file, fileIndex) => ( // fileIndex is added here to hold array element index
<li key={file.path}>
<Button className="ml-3" close />
{file.path} - {(file.size / 1024).toFixed(1)} KB
<button type="button" onClick={() => handleDelete(fileIndex)}
</li>
))}
</ul>
</div>;
You can create the key array that you want to remove.
function Files(){
const [dis, setDis] = useState([]);
const removeHandler = (key) => {
setDis(dis.push(key))
}
return(
<div>
<h5 className="col-lg-4 mt-4">Selected Files</h5>
<ul className="nobull text-sm">
{files.map((file, key) => (
!fruits.includes(key) && (
<li key={file.path}>
<Button className="ml-3" close onClick={()={removeHandler(key)}}/>
{file.path} - {(file.size / 1024).toFixed(1)} KB
</li>
)
))}
</ul>
</div>;
)
}
you could use a function like this const removeFile = id =>{ const updatedFiles = files.filter(file => file.id !== FileId)
setFiles(updatedFiles)
}
<Button className="ml-3" onClick={() => removeFile(id)} close />

Mapping nested array inside mapped array in React JSX

I'm trying to write a dashboard sidebar which has a couple of "primary" buttons which (via Bootstrap) collapse a number of "secondary" buttons. I want to be able to easily update and style the whole thing so writing static markup is out of the picture. Here is one object out of the array:
const menuArray = [
{
primaryText: "Applications",
primaryIcon: "fa fa-rocket",
primaryURL: "/applications",
secondaries: [
{
secondaryText: "Softwares",
secondaryURL: "/softwares",
},
{
secondaryText: "Videogames",
secondaryURL: "/videogames",
},
{
secondaryText: "Tools",
secondaryURL: "/tools",
},
],
},
]
And here is the function rendering the array which i'm simply calling in the JSX markup by {renderMenuArray}
const renderMenuArray = menuArray.map((menuItem) => (
<li className="py-2">
<button
data-target={`#${menuItem.primaryText}Submenu`}
data-toggle="collapse"
aria-expanded="false"
className="btn btn-dark btn-menu btn-block pl-0 mb-1"
>
<Link to={menuItem.primaryURL}>
<span className="mr-3">
<i className={menuItem.primaryIcon}></i>
</span>
{menuItem.primaryText}
</Link>
</button>
<div
className="card-body collapse ml-5"
id={`${socialItem.primaryText}Submenu`}
>
<ul className="list-unstyled">
<li>
<Link className="small" to="/applications/softwares">
<span className="mr-3">
<i className="fa fa-chevron-right"></i>
</span>
Softwares
</Link>
</li>
</ul>
</div>
));
I can render the "primary" objects with no problem at all, but I want each "primary" object ( each iteration of the parent array) to each iterate through the count of "secondaries" array ( which is going to be different for each "primary" object).
I'm a beginner developer.
The object passed into the callback function for the map, menuItem has the included property secondaries. You can use map on this property since secondaries is an array, simply place the map inside of your JSX.
<div
className="card-body collapse ml-5"
id={`${socialItem.primaryText}Submenu`}
>
<ul className="list-unstyled">
{menuItem.secondaries.map((subItem) => {
...
})
</ul>
</div>
P.S. you forgot to close your last div tag, and you have a second </li> instead of a </ul>
This'll work (made it a bit more functional, to give you an example of what's possible with functional React components)
const menuArray = [
{
primaryText: "Applications",
primaryIcon: "fa fa-rocket",
primaryURL: "/applications",
secondaries: [
{
secondaryText: "Softwares",
secondaryURL: "/softwares"
},
{
secondaryText: "Videogames",
secondaryURL: "/videogames"
},
{
secondaryText: "Tools",
secondaryURL: "/tools"
}
]
}
];
export default function App(props) {
function renderSecondaryMenu(items) {
return items.map(secondaryItem => {
return (
<li>
<Link className="small" to={secondaryItem.secondaryURL}>
<span className="mr-3">
<i className="fa fa-chevron-right" />
</span>
{secondaryItem.secondaryText}
</Link>
</li>
);
});
}
function renderMenuArray() {
return menuArray.map(menuItem => {
return (
<li className="py-2">
<button
data-target={`#${menuItem.primaryText}Submenu`}
data-toggle="collapse"
aria-expanded="false"
className="btn btn-dark btn-menu btn-block pl-0 mb-1"
>
<Link to={menuItem.primaryURL}>
<span className="mr-3">
<i className={menuItem.primaryIcon} />
</span>
{menuItem.primaryText}
</Link>
</button>
<div
className="card-body collapse ml-5"
id={`${menuItem.primaryText}Submenu`}
>
<ul className="list-unstyled">
{renderSecondaryMenu(menuItem.secondaries)}
</ul>
</div>
</li>
);
});
}
return <div className="App">{renderMenuArray()}</div>;
}
I don't think you gain a lot from defining the sidebar as an object, unless you are using the same Sidebar component with different sets of buttons and you wanna be able to switch between them. JSX is already a markup language, so it's declarative.
You could define simply the Sidebar as
const Sidebar = () => (
<PrimaryItem text="Applications" icon="fa fa-rocket" url="/applications">
<SecondaryItem text="Softwares" url="/softwares" />
<SecondaryItem text="Videogames" url="/videogames" />
<SecondaryItem text="Tools" url="/tools" />
</PrimaryItem>
)
And then implement each component as you need to display them. I think this is cleaner and easier to maintain and modify.

React js - pass value to child to parent to another child

I am trying to pass the data from Child > parent > child
Child
{this.state.data.map((item, index) => (
<li className='card' key={index}>
<span>{item.continent} </span>
<ul className="accordion-body">
{item.regions.map((c, i) => (
<li key={i} onClick={this.props.toggleContent}>
<img src={c.flag}/> {c.country}
</li>
))}
</ul>
</li>
))}
Basically I need to get selected country and some other values from the child and pass to parent
and pass those values to another child.
My Parent
<div className="modal-header">
<h2>Choose your {title}</h2>
<a href="#" className="model-close" data-dismiss="modal" aria-label="Close"><i
className="fa fa-times-circle"></i></a>
</div>
<div className="modal-body">
{showCountry && <CountryList toggleContent={this.toggleContent}/>}
{showLanguages && <RegionList country={country} flag={flag} languages={languages}
toggleContent={this.toggleContentRegion.bind(this)}/>}
</div>
and
toggleContent = () => {
this.setState({
...this.state,
showCountry: !this.state.showCountry,
showLanguages: !this.state.showLanguages,
title: 'language',
country: 'country',
languages: [],
flag: 'flag'
});
}
I tried to use below
<li key={i} onClick={this.props.toggleContent(c.country)}>
<img src={c.flag}/> {c.country}
</li>
and access it from parent
toggleContent = (country) => {
this.setState({
...this.state,
showCountry: !this.state.showCountry,
showLanguages: !this.state.showLanguages,
title: 'language',
country: country,
languages: [],
flag: 'flag'
});
}
But, my components not working correctly When do that and always shows the 2 child component.
Are there any proper way to pass the data to parent from a json array?
So the best way I would handle this would be to make the import your parent class components into the child , place it at the very top of the child JSX but hide it by default. The modal would be fixed, background covering the full page and at a z-index higher than the rest of the child components, so that way only the modal contents are the only accessible things . You would have a state that "toggles on" the modal for each click of the item list and a close button that toggles it off. You would update the modal content and toggle it on for every click
In terms of the second child, you can just show it on the same modal
Found a way to do this :)
render() {
var toggleContent = this.props.toggleContent;
return (
<div className="modal-wrapper">
<ul className="country-list">
{this.state.data.map((item, index) => (
<li className='card' key={index}>
<span>{item.continent} </span>
<ul className="accordion-body">
{item.regions.map((c, i) => (
**<li key={i} onClick={() => toggleContent(c.country,c.flag, c.languages, c.region)} >**
<img src={c.flag}/> {c.country}
</li>
))}
</ul>
</li>
))}
</ul>
</div>
);
}
Changed below line
onClick={() => toggleContent(c.country,c.flag, c.languages, c.region)

Build dropdown menu with array passed from parent component [duplicate]

This question already has answers here:
map function not working in React
(3 answers)
Index inside map() function
(4 answers)
Closed 25 days ago.
I am trying to build a dropdown-menu and add data from my array to the dropdown-item. My current code isn't returning anything into my const Users. How can I use the array to add data into the dropdown-item?
UserDisplay component
const UserDisplay = ({ users }) => {
const Users = users.map(user => {
let i = 0;
<a className="dropdown-item" href="#">
{user[i]}
</a>;
i++;
});
return (
<div className="dropdown-menu" id="users">
<a className="dropdown-item" href="#">
Online Users
</a>
<div className="dropdown-divider" />
{Users}
</div>
);
};
Parent Component ChatLayout
return (
<div className="chat navbar fixed-bottom">
<div className="btn-group dropup">
<button
type="button"
className="btn btn-secondary dropdown-toggle"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
>
Chat
</button>
<UserDisplay users={[this.state.users]} />
</div>
<ul id="messages">
<div />
</ul>
<form onSubmit={this.onSubmit}>
<textarea
name="message"
placeholder="Enter your message here"
autoComplete="off"
type="submit"
onKeyDown={this.onEnterPress}
value={this.state.message}
onChange={this.onChange}
/>
<input type="submit" className="btn btn-info btn-block mt-4" />
</form>
</div>
);
You don't need to define and iterate i.. the .map already keeps track of the array index. Assuming users has data it should work like this...
UserDisplay(users) {
const Users = users.map((user,i) => {
return (
<a className="dropdown-item" key={i} href="#">
{user}
</a>)
});
return (
<div className="dropdown-menu" id="users">
<a className="dropdown-item" href="#">
Online Users
</a>
<div className="dropdown-divider" />
{Users}
</div>
);
};
Working Codeply: https://www.codeply.com/go/DnqpGhozra
You are destructing props object and get users out of it so its fine.
basically map returns a list of array so you dont have return anything.
You need to iterate to the first element of users like
const Users = users[0].map((user,i) => {
console.log(user);
return (
<a className="dropdown-item" key={i} href="#">
{user}
</a>)
});
OR just pass users directly
<UserDisplay users={this.state.users} />

Categories

Resources