Removing li items with Button onClick - javascript

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 />

Related

Each child in a list should have a unique "key" prop while nested list iteration

I have this React code:
export default function Technologies({ technologies }) {
return (
<>
{ Object.keys(technologies).map((key, i) => (
<span>
<span className={styles.post}><h3 className={'bold300'}>{key}</h3></span>
<div className={styles.techList}>
<ul key={i}>
{ Object.keys(technologies[key]).map((key2, idx) => (
<li key={idx}>{key2}
{ technologies[key][key2].map(key3 => (
<span key={key3.name} className={styles.badge}><Image src={key3.name} width={key3.w} height={key3.h} /></span>
)) }
</li>
)) }
</ul>
</div>
</span>
)) }
</>
)
}
Here you can see nested iteration, and everywhere I use i or idx to create unique key for list, but still keep getting warning for this string:
...
<ul key={i}>
...
As I said, I know what this error means, and even know how to fix, but not in this case, I just don't know, where I should put key to prevent this warning. Thanks!
The key should be present on the root element. So, the first key should be on the span and not on the ul.
export default function Technologies({ technologies }) {
return (
<>
{Object.keys(technologies).map((key, i) => (
<span key={i}>
<span className={styles.post}>
<h3 className={"bold300"}>{key}</h3>
</span>
<div className={styles.techList}>
<ul>
{Object.keys(technologies[key]).map((key2, idx) => (
<li key={idx}>
{key2}
{technologies[key][key2].map((key3) => (
<span key={key3.name} className={styles.badge}>
<Image src={key3.name} width={key3.w} height={key3.h} />
</span>
))}
</li>
))}
</ul>
</div>
</span>
))}
</>
);
}

How to optimize toggling className between different menu items by React?

I have header component, where I want to toggle className between all the elements of menu (if one of the elements of menu is active and user is clicking to another element - this element become active and all others no). I have a code like this
import React, { useState } from 'react';
import './header.scss';
export const Header = ({ favoriteCount }) => {
const [activeIndex, setActiveIndex] = useState(0);
function toggleClass(index) {
setActiveIndex(index);
}
return (
<header className="header">
<div className="container header-container">
<ul className="header-menu">
<li>
<a
className={
activeIndex === 0
? 'header-menu__link active'
: 'header-menu__link'
}
onClick={() => {
toggleClass(0);
}}
href="##"
>
Characters
</a>
</li>
<li>
<a
className={
activeIndex === 1
? 'header-menu__link active'
: 'header-menu__link'
}
onClick={() => {
toggleClass(0);
}}
href="##"
>
Favorites
</a>
</li>
</ul>
<div className="header-favorite-count">
<i className="far fa-heart"></i>
{favoriteCount}
</div>
</div>
</header>
);
};
and styles to visualise toggling classes
&-menu__link {
color: lightgray;
}
.active {
color: #fff;
}
This approach is working but looks creepy. Maybe somebody knows how to optimize it?
I wouldn't use the index, I'd use the text of the item. I'd also include that text in the href so that there's an indication of what the anchor leads to. To avoid repeated code, you might put the menu items in a reusable array, something like this:
const menuItems = [
"Characters",
"Favorites",
];
export const Header = ({ favoriteCount }) => {
const [activeItem, setActiveItem] = useState("");
const setActiveItem = useCallback((event) => {
setActiveItem(event.currentTarget.href.substring(2));
}, []);
const list = menuItems.map(item =>
<li key={item}>
<a
className={`header-menu__link ${item === activeItem ? "active" : ""}`}
onClick={setActiveItem}
href={"##" + item}>
{item}
</a>
</li>
);
return (
<header className="header">
<div className="container header-container">
<ul className="header-menu">
{list}}
</ul>
<div className="header-favorite-count">
<i className="far fa-heart"></i>
{favoriteCount}
</div>
</div>
</header>
);
};

React/JS How would I assign a specific mapped element to a state?

My search component returns a mapped list of results based on the input. Depending on the list element clicked, I want to assign it to my current stock state but I am not sure how I would access that specific element.
const selectStock = ()=>{
setSearch("");
setCurrentStock();
}
return (
<div className="searchContainer">
<form className="searchBar">
<input
className="search"
type="text"
placeholder="Search Ticker Symbol"
onChange={handleSearch}
/>
</form>
<div className="searchResults">
<ul>
{/* {stockNames.map((stockname) => {
const { name, symbol} = stockname;
return (
<li className="displaySearch" onClick={selectStock} key={symbol}>
<p>{name} ({symbol})</p>
</li>
);
})} */}
</ul>
</div>
</div>
);
}
First, you'll want to change your selectStock function to accept the stockName to which it should be set. That should be passed to your setCurrentStock function:
const selectStock = (nextStock) => {
setSearch("");
setCurrentStock(nextStock);
}
Then, pass an arrow function through to the onClick function for the row that you select:
<div className="searchResults">
<ul>
{stockNames.map((stockname) => {
const { name, symbol } = stockname;
return (
<li className="displaySearch" onClick={() => selectStock(stockname)} key={symbol}>
<p>{name} ({symbol})</p>
</li>
);
})}
</ul>
</div>
What this does is essentially create a new function for each row that's specific to itself. When that row is clicked, it triggers its own unique onClick, which passes its own stockname value through to selectStock.
You can pass the selectedStock into the selectStock function by making it a ES6 function.
See below:
const selectStock = (selectedStock)=>{
setSearch("");
setCurrentStock(selectedStock);
}
return (
<div className="searchContainer">
<form className="searchBar">
<input
className="search"
type="text"
placeholder="Search Ticker Symbol"
onChange={handleSearch}
/>
</form>
<div className="searchResults">
<ul>
{/* {stockNames.map((stockname) => {
const { name, symbol} = stockname;
return (
<li className="displaySearch" onClick={()=>selectStock(stockName)} key={symbol}>
<p>{name} ({symbol})</p>
</li>
);
})} */}
</ul>
</div>
</div>
);
You can pass other variables in the similar way if required.

Hide other previous div/dropdown React

I am wanting to hide other sibling divs (dropdowns in my case) when I click the statusPillDropdown
so far I click I am setting the status to true and opening the div,
{DropDown ${toggleStatusDropdown ? "open": ""}}
Do I just need to set the state to false for previously opened ones? Not sure how to do this.
thank you
import React, { useState } from "react";
import "./StatusPillDropdown.scss";
function StatusPillDropdown({
cellData,
rowItemId,
onStatusPillDropdownChange
}) {
const [toggleStatusDropdown, setToggleStatusDropdown] = useState();
const toggleDropdown = (action, rowItemId, e) => {
if (action === "pillClick") {
setToggleStatusDropdown(true);
} else {
onStatusPillDropdownChange(rowItemId, e.target.getAttribute("value"));
setToggleStatusDropdown(false);
}
};
const renderstatusPillDropdown = (cellData, rowItemId) => (
<React.Fragment>
<span
className="statusPillDropdown"
onClick={() => toggleDropdown("pillClick", rowItemId)}
>
<span className={`status-pill ${cellData.type}`}>{cellData.text}</span>
</span>
<div className="status">
<div className="dropdown-container">
<div className={`DropDown ${toggleStatusDropdown ? "open" : ""}`}>
<ul>
<li
value="Information only"
onClick={e => toggleDropdown("liClick", rowItemId, e)}
>
<span></span>Information only
</li>
<li
value="Unresolved"
onClick={e => toggleDropdown("liClick", rowItemId, e)}
>
<span className="unresolved"></span>Unresolved
</li>
<li
value="Partially Resolved"
onClick={e => toggleDropdown("liClick", rowItemId, e)}
>
<span className="partyResolved"></span>Partially Resolved
</li>
<li
value="Fully Resolved"
onClick={e => toggleDropdown("liClick", rowItemId, e)}
>
<span className="resolved"></span>Fully Resolved
</li>
</ul>
</div>
</div>
</div>
</React.Fragment>
);
return (
<React.Fragment>
{renderstatusPillDropdown(cellData, rowItemId)}
</React.Fragment>
);
}
export default StatusPillDropdown;

toggle background color on a function - ReactJS

When I clicked a link it renders a view based on the "id" from a JSON. I need to apply a background color when a certain view renders. And I should toggle the Style.
This code shows the crawl when I clicked a particular link.
handleCrawl = e => {
const { id } = e.target;
this.setState(current => ({
showCrawl: { [id]: !current.showCrawl[id] }
}));
};
This is my render method where Ia am mapping the links and the additional details on JSON
render() {
return (
<div class="d-flex" id="wrapper">
<div class="bg-light border-right" id="sidebar-wrapper">
<h1 class="sidebar-heading">API</h1>
<ul class="list-group list-group-flush">
{this.state.apis.map(api => (
<li><a class="list-group-item list-group-item-action bg-light" key={api.id}
id={api.id}
onClick={this.handleCrawl}>{api.title}</a></li>
))}
</ul>
</div>
<div id="page-content-wrapper">
<div class="container-fluid">
{this.state.apis.map(api => (
<div
key={api.id}
id={api.id}>
{this.state.showCrawl[api.id] && (
<SwaggerUI url={api.opening_crawl}/>
)}
</div>
))}
</div>
</div>
</div>
);
}
Not sure if it answers your question.
You can toggle the style conditionally.
{this.state.apis.map(api => (
<div
key={api.id}
id={api.id}
className={this.state.showCrawl[api.id]?"some-specific-style":"default-or-empty"}
>
{this.state.showCrawl[api.id] && (
<SwaggerUI url={api.opening_crawl}/>
)}
</div>
))}

Categories

Resources