How to change the button colour when it is clicked - javascript

I have this set of buttons from A to Z when I click on the particular alphabet the brands related to that letter will pop up. I have tried the below code but it is applying for all the buttons when I click only one button. How do I solve it
let brandList = 'ABCEDEFGHIJKLMNOPQRSTUVWXYZ'.split("");
constructor(props) {
super(props)
this.state = {
bgColor: ""
}
}
getBrandSortData(){
return(
<div className="BrandPageList_AlphabetContainer">
<button value="all" className="BrandPageList_AllButton" onClick={this.handleClick}>All</button>
{brandList.map((item,index) =>
{
let disbaled = !this.isBrandCharacterAvailable(item)
return(
<button
disabled= {disbaled}
value={item}
key={index}
block="BrandPageList_AlphabetButtons"
mods = {{enabled : !disbaled}}
onClick={this.handleClick}
style={{backgroundColor: this.state.bgColor}}
>
{item}
</button>
)}
)}
</div>
)
}
handleClick = event =>{
const brandValues = event.target.value
if(brandValues === "all"){
console.log()
return this.setAllBrands()
}
else{
let brandSortDataByCharacter = this.state.brandSortData[brandValues]
this.setState({
allBrands:
{
[brandValues]: brandSortDataByCharacter
},
bgColor: "red"
})
}
}
This is the imageThanks in advance

Instead of using the event object to determine what letter you clicked on, you can pass the letter to the click handler when you render it.
Here's an example of how you can achieve this. I'm using a functional component with hooks, since this is the recommended way, but you can do the same in a class component:
const Alphabet = () => {
const [active, setActive] = useState();
return (
<div className='alphabet'>
{'ABCEDEFGHIJKLMNOPQRSTUVWXYZ'.split('').map(char => (
<div
className={`letter ${char === active ? 'active' : ''}`}
onClick={() => setActive(char)}>{char}</div>
))}
</div>
);
};
And here's a live example

Related

Make other block disappear when chose a value

How can I make other filter button disappear when picked 1 value.
Here is my code base:
const FilterBlock = props => {
const {
filterApi,
filterState,
filterFrontendInput,
group,
items,
name,
onApply,
initialOpen
} = props;
const { formatMessage } = useIntl();
const talonProps = useFilterBlock({
filterState,
items,
initialOpen
});
const { handleClick, isExpanded } = talonProps;
const classStyle = useStyle(defaultClasses, props.classes);
const ref = useRef(null);
useEffect(() => {
const handleClickOutside = event => {
if (ref.current && !ref.current.contains(event.target)) {
isExpanded && handleClick();
}
};
document.addEventListener('click', handleClickOutside, true);
return () => {
document.removeEventListener('click', handleClickOutside, true);
};
}, [isExpanded]);
const list = isExpanded ? (
<Form>
<FilterList
filterApi={filterApi}
filterState={filterState}
name={name}
filterFrontendInput={filterFrontendInput}
group={group}
items={items}
onApply={onApply}
/>
</Form>
) : null;
return (
<div
data-cy="FilterBlock-root"
aria-label={itemAriaLabel}
ref={ref}
>
<Menu.Button
data-cy="FilterBlock-triggerButton"
type="button"
onClick={handleClick}
aria-label={toggleItemOptionsAriaLabel}
>
<div>
<span>
{name}
</span>
<svg
width="8"
height="5"
viewBox="0 0 8 5"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6.97291 0.193232C7.20854"
fill="currentColor"
/>
</svg>
</div>
</Menu.Button>
<div>
<div>
{list}
</div>
</div>
</div>
);
};
I am trying to achieve when I chose 1 value inside filter block the other block will disappear. Anyone have idea how can I work on this?
I am using React and Redux for this project
Thank you for helping me on this!!!!
Update:
Added parent component for FilterBlock.ks:
const FilterSidebar = props => {
const { filters, filterCountToOpen } = props;
const talonProps = useFilterSidebar({ filters });
const {
filterApi,
filterItems,
filterNames,
filterFrontendInput,
filterState,
handleApply,
handleReset
} = talonProps;
const filterRef = useRef();
const classStyle = useStyle(defaultClasses, props.classes);
const handleApplyFilter = useCallback(
(...args) => {
const filterElement = filterRef.current;
if (
filterElement &&
typeof filterElement.getBoundingClientRect === 'function'
) {
const filterTop = filterElement.getBoundingClientRect().top;
const windowScrollY =
window.scrollY + filterTop - SCROLL_OFFSET;
window.scrollTo(0, windowScrollY);
}
handleApply(...args);
},
[handleApply, filterRef]
);
const [selectedBlock, setSelectedBlock] = useState();
const filtersList = useMemo(
() =>
Array.from(filterItems, ([group, items], iteration) => {
const blockState = filterState.get(group);
const groupName = filterNames.get(group);
const frontendInput = filterFrontendInput.get(group);
if (selectedBlock) {
return (
<FilterBlock
key={group}
filterApi={filterApi}
filterState={blockState}
filterFrontendInput={frontendInput}
group={group}
items={items}
name={groupName}
onApply={handleApplyFilter}
initialOpen={iteration < filterCountToOpen}
iteration={iteration}
id={selectedBlock}
onSelected={setSelectedBlock}
/>
);
}
return (
<FilterBlock
key={group}
filterApi={filterApi}
filterState={blockState}
filterFrontendInput={frontendInput}
group={group}
items={items}
name={groupName}
onApply={handleApplyFilter}
initialOpen={iteration < filterCountToOpen}
iteration={iteration}
id={selectedBlock}
onSelected={setSelectedBlock}
/>
);
}),
[
filterApi,
filterItems,
filterNames,
filterFrontendInput,
filterState,
filterCountToOpen,
handleApplyFilter
]
);
return (
<div className="container px-4 mx-auto">
<Menu
as="div"
className="my-16 justify-center flex flex-wrap py-5 border-y border-black border-opacity-5"
>
{filtersList}
</Menu>
</div>
);
};
console.log(filterItems) and it gave me this output:
Map(3) {'markforged_printer_type' => Array(3),
'markforged_material_filter' => Array(7), 'markforged_parts_filter' =>
Array(7)} [[Entries]] 0 : {"markforged_printer_type" => Array(3)} 1 :
{"markforged_material_filter" => Array(7)} 2 :
{"markforged_parts_filter" => Array(7)}
Updated Answer
From the changes you provided, you are using useMemo() and useCallback(). Those kinds of optimizations in general are not necessary to be made or even decrease performance in some cases. Check this article from Kent C. Dodds (others can be easily found about the theme) to explain some issues with it.
About the changes, as a suggestion, you could use the .map()/.filter() functions instead Array.from().
You are splitting logic about rendering different components with the useMemo(), and this could be changed into one component instead of this whole logic inside the Parent component. (For my suggestion this will be not the case)
As a guide to your code, you could use something like this:
const FilterSidebar = ({ filters, filterCountToOpen }) => {
// here you have the state to control if there is a block selected
const [selectedGroup, setSelectedGroup] = useState();
const {
// only those are needed for this example
filterItems,
handleApplyFilter
} = useFilterSidebar({ filters });
return (
<div className="container px-4 mx-auto">
<Menu
as="div"
className="my-16 justify-center flex flex-wrap py-5 border-y border-black border-opacity-5"
>
{filterItems.map(([group, items], iteration) => {
const groupName = filterNames.get(group);
if (selectedGroup !== null && selectedGroup !== groupName) {
// returning null here should not render anything for this list item
return null;
}
return (
<FilterBlock
// pass all your extra props here
// but the important one is the `onApply`
onApply={(...args) => {
setSelectedGroup((prev) => prev !== null ? null : groupName);
return handleApplyFilter(...args);
}}
/>
);
}}
</Menu>
</div>
);
};
If you see any null on your screen, you could use first the .filter() and then the .map() or combine both with a single .reduce(). It should be something like this:
{filterItems
.filter(([group, items]) => selectedGroup === null || selectedGroup === filterNames.get(group))
.map(([group, items], iteration) => {
const groupName = filterNames.get(group);
return (
<FilterBlock
// pass all your extra props here
// but the important one is the `onApply`
onApply={(...args) => {
setSelectedGroup((prev) => prev !== null ? null : groupName);
return handleApplyFilter(...args);
}}
/>
);
}}
With your update, it is possible to see that you can select by the group (instead of the block which it was called before). Also, you can just add a little change to your onApply prop and that will save and re-render the list. If the selectedGroup is already there, removing the filter will show the other sections. Eventually, you'll need to trim this logic to accommodate other things such as selecting more than one filter and checking for that and so on.
Original Answer
From what you described I'm assuming what you want is: You have 3 FilterBlocks on your screen. Once a user selects one checkbox inside one opened "select" (that you are calling FilterBlock), you want the other FilterBlocks disappear from the screen and just the single FilterBlock with the selected option to stay at the screen (the other 2 will be hidden).
If that's your case, there are some possible options to achieve that but the easiest one is controlling this on a Parent Component: You can pass a prop from the parent component named something like onSelected, give an id to each FilterBlock, and when one filter is selected inside, you trigger that callback with the id from that FilterBlock.
const Parent = () => {
const [selectedBlock, setSelectedBlock] = useState();
if (selectedBlock) {
return <FilterBlock id={selectedBlock} onSelected={setSelectedBlock} />
}
return (
<>
<FilterBlock id="filter-block-1" onSelected={setSelectedBlock} />
<FilterBlock id="filter-block-2" onSelected={setSelectedBlock} />
<FilterBlock id="filter-block-2" onSelected={setSelectedBlock} />
</>
)
}
const FilterBlock = ({ id, onSelected }) => (
return (
<>
<button onClick={() => onSelected(id)}>Select filter block {id}</button>
<button onClick={() => onSelected()}>Unselect filter block {id}</button>
</>
);

SetState overwrites previous state even with spread operator React.JS

I'm facing an issue with setState inside my handleChange.
So here in code after clicking addList a div with input and button will appear, then when i type inside input the input state will update and after clicking Add button the div will disappear.
so my problem is next time when clicking addList the value of previous input is still there and the hideAddList handler does not set the input state to empty and also when I type in the new opened div the previous input state will overwrite. even with indexing and spread operator its still same problem.
what should I do?
export class myClass extends Component {
constructor(props) {
super(props);
this.state = {
input: [{ title: '' }]
};
this.addList = this.addList.bind(this);
this.hideAddList = this.hideAddList.bind(this);
this.titleHandleChange = this.titleHandleChange.bind(this);
}
addList() {
var x = document.getElementById("btn-list")
var y = document.getElementById("add-button")
x.style.display = 'none'
y.style.display = ''
}
hideAddList() {
var x = document.getElementById("btn-list")
var y = document.getElementById("add-button")
x.style.display = ''
y.style.display = 'none';
this.setState(prevState => ({ input: [...prevState.input, {title:''}]}))
}
HandleChange(e, index){
const { name, value } = e.target;
const list = [...this.state.input];
list[index][name] = value;
this.setState({ input: list});
}
render() {
return (
<div>
<button id="btn-list" className="btn btn-default btn-list" type="submit" onClick={this.addList}>Add Another List</button>
{this.state.input.map((x, i) => {
return (
<div key={i} id="add-button" className="add-button" style={{ display: "none" }}>
<input id="input" type="text" onChange={(e) => {this.HandleChange(e, i)}} value={x.title} name="title" className="form-control add-input" />
<button className="btn btn-default btn-list-add" onClick={this.hideAddList} type="submit">Add</button>
</div>
)})}
</div>
)
}
}
export default myClass
from the code you provided, you will always get the first "add-button" element each time you call addList, because all of your list items have the same id.
{this.state.input.map((x, i) => {
...
<div key={i} id="add-button" ...> // here! they got the same id!
so what happened here is that you are actually editing the first item all the time. you will need to add different id to your elements. and the AddList should get the last item index.
for example:
AddList()
...
{this.state.input.map((x, i) => {
return (
<div key={i} id={`add-button-${i}`} .... // here! add unique id for each item!
the whole code should be like this:
export default class myClass extends React.Component {
constructor(props) {
super(props);
this.state = {
input: [{title: ''}],
};
this.addList = this.addList.bind(this);
this.hideAddList = this.hideAddList.bind(this);
this.titleHandleChange = this.titleHandleChange.bind(this);
}
addList() {
var lastItemIndex = this.state.input.length - 1; // you need to get the last item's index to make sure that you display the latest item
var x = document.getElementById('btn-list');
var y = document.getElementById(`add-button-${lastItemIndex}`);
x.style.display = 'none';
y.style.display = '';
}
hideAddList(i) {
var x = document.getElementById('btn-list');
var y = document.getElementById(`add-button-${i}`);
x.style.display = '';
y.style.display = 'none';
this.setState(prevState => ({input: [...prevState.input, {title: ''}]}));
}
titleHandleChange(e, index) {
const {name, value} = e.target;
const list = [...this.state.input];
list[index][name] = value;
this.setState({input: list});
}
render() {
return (
<div>
<button
id="btn-list"
className="btn btn-default btn-list"
type="submit"
onClick={this.addList}>
Add Another List
</button>
{this.state.input.map((x, i) => {
return (
<div
key={i}
id={`add-button-${i}`}
className="add-button"
style={{display: 'none'}}>
<input
id="input"
type="text"
onChange={e => {
this.titleHandleChange(e, i);
}}
value={x.title}
name="title"
className="form-control add-input"
/>
<button
className="btn btn-default btn-list-add"
onClick={() => this.hideAddList(i)}
type="submit">
Add
</button>
</div>
);
})}
</div>
);
}
}
for debugging, maybe you can try to log index out in titleHandleChange, so you can find out which item that you're actually editing.
ps, you could write export default class MyClass extends ... so you don't need to write export default MyClass at the end of the file again.
The state has already been changed correctly. You can add a console log to see it:
render() {
console.log(this.state);
return (
...
The reason that it is not showing on your screen is the {display: 'none'} that you set for id 'add-button'. Your var y = document.getElementById("add-button") will just get the first element, but not the whole list of elements.
FYI it is not quite right to use document.getElementById in a react project for your case. It should be done by state. Here is a complete example:
export class MyClass extends Component {
constructor(props) {
super(props);
this.state = {
input: [{title: ''}],
showAnotherListBtn: true,
showList: false,
};
}
onClickAnotherListBtn = () => {
this.setState({
showAnotherListBtn: false,
showList: true,
});
}
addList = () => {
this.setState({
input: [...this.state.input, {title: ''}],
});
}
handleChange(e, index) {
const {name, value} = e.target;
const list = [...this.state.input];
list[index][name] = value;
this.setState({input: list});
}
render() {
console.log(this.state);
return (
<div>
{this.state.showAnotherListBtn ?
<button id="btn-list" className="btn btn-default btn-list" type="submit" onClick={this.onClickAnotherListBtn}>Add Another
List</button> : null}
{this.state.showList && this.state.input.map((x, i) => {
return (
<div key={i} id="add-button" className="add-button">
<input id="input" type="text" onChange={(e) => {
this.handleChange(e, i)
}} value={x.title} name="title" className="form-control add-input"/>
<button className="btn btn-default btn-list-add" onClick={this.addList} type="submit">Add</button>
</div>
)
})}
</div>
)
}
}
export default MyClass
As you can see from the above code, you an just use a boolean state to determine whether you should show the element or not.
Hope this helps ;)

React/Redux Changing background colour of button in nested array using state

I've been scratching my head over this for ages now.
I am trying to change the background colour of a specific button that is in a nested array.
I have an array of names in pairs that I loop over twice using a map, once to get the pair and once again to get the value. I output and assign the values to a button for each and am displaying the pairs together (E.g. each pair is indexed 0 and 1).
When I click on the button I wish to change only the background colour of the selected button. Currently all the buttons change colour. The issue being is that the state of the buttons effects all of them when I use a boolean to define the selection.
The handler I am using to do this also adds the value of the button to an array to be passed into global state later on as well.
Any help with this would be greatly greatly appreciated as I can't seem to find a way past it. Thanks!
import React, { Component } from "react";
import "../../App.scss";
import { Link } from "react-router-dom";
import Button from "../Button/Button";
class Matches extends Component {
constructor(props) {
super(props);
this.state = {
champ: [],
winningPlayers: [],
selected: false,
};
this.handleAddWinners = this.handleAddWinners.bind(this);
this.handleRound = this.handleRound.bind(this);
}
// Adds winners to a local array which is then sent
// to the global array using the handleNextRound action.
handleAddWinners = (e) => {
const winner = e.target.value;
const { champ } = this.state;
const { round } = this.props;
if (round !== 3) {
this.setState({
selected: !false,
winningPlayers: [...this.state.winningPlayers, winner],
});
} else {
this.setState({ champ: [...champ, winner] });
}
};
handleRound = () => {
const { round, handleNextRound, handleChampion } = this.props;
round !== 3 ? handleNextRound(this.state) : handleChampion(this.state);
this.setState({ winningPlayers: [] });
};
render() {
const { pairs, round, handleClear, roundWinners, champion } = this.props;
const { winningPlayers, selected, champ } = this.state;
const semi = roundWinners[0];
const final = roundWinners[1];
const champName = champion.map((item) => item);
const reset =
round !== 4 ? "block__reset__tournament" : "block__reset__new-game";
const newGame = `${round !== 4 ? "Reset" : "New Game?"}`;
const buttonClick = `${selected ? "selected" : "block__player"}`;
return (
<>
<div classname="container__wrapper">
<div className="container__tournament">
{round === 1 ? (
<section className="block__round ">
{pairs.map((item, index) => (
<div className="pairs" key={index}>
{item.map((names, index) => (
<Button
key={index}
handleClick={(e) => this.handleAddWinners(e)}
label={names}
buttonClass={buttonClick}
value={names}
/>
))}
</div>
))}
</section>
) : round === 2 ? (
<section className="block__round ">
{semi.map((names, index) => (
<div className="pairs" key={index}>
{names.map((names, index) => (
<Button
key={index}
handleClick={(e) => this.handleAddWinners(e, "value")}
label={names}
buttonClass={buttonClick}
value={names}
/>
))}
</div>
))}
</section>
) : round === 3 ? (
<section className="block__round ">
{final.map((names, index) => (
<div className="pairs" key={index}>
{names.map((names, index) => (
<Button
key={index}
handleClick={(e) => this.handleAddWinners(e, "value")}
label={names}
buttonClass={buttonClick}
value={names}
/>
))}
</div>
))}
</section>
) : (
<section className="block__champion">
<p className="champion__greeting">
Congratulations
<br />
<span className="champion__name">{champName}!</span>
<br /> You've won the whole shebang!
</p>
</section>
)}
<Button
buttonClass={`${
round !== 4 ? "block__next-round" : "button__notActive"
}`}
label={`${round !== 3 ? "Next Round" : "See Winner"}`}
handleClick={this.handleRound}
disabled={disabled}
/>
<Link to={"/"} className={reset}>
<Button
buttonClass={reset}
handleClick={handleClear}
label={newGame}
/>
</Link>
</div>
</div>
</>
);
}
}
export default Matches;
This is the component that is handling most of this.
First I would like to say that you should always avoid from using array's index as keys. That is, unless your array is always at the same size and order.
Having said that - what you want to do is to know which button was selected - right?
So you need to store the last button that was selected. Because you don't use any ids anywhere, you can use the index of the pair and the index of the button to know which button was clicked.
Here's an example - I've changed only the round1 and the state code.
import React, { Component } from "react";
import "../../App.scss";
import { Link } from "react-router-dom";
import Button from "../Button/Button";
class Matches extends Component {
constructor(props) {
super(props);
this.state = {
champ: [],
winningPlayers: [],
selected: null,
};
this.handleAddWinners = this.handleAddWinners.bind(this);
this.handleRound = this.handleRound.bind(this);
}
// Adds winners to a local array which is then sent
// to the global array using the handleNextRound action.
handleAddWinners = (e, pairIndex, itemIndex) => {
const winner = e.target.value;
const { champ } = this.state;
const { round } = this.props;
if (round !== 3) {
this.setState({
selected: `${pairIndex}-${itemIndex}`,
winningPlayers: [...this.state.winningPlayers, winner],
});
} else {
this.setState({ champ: [...champ, winner] });
}
};
handleRound = () => {
const { round, handleNextRound, handleChampion } = this.props;
round !== 3 ? handleNextRound(this.state) : handleChampion(this.state);
this.setState({ winningPlayers: [] });
};
render() {
const { pairs, round, handleClear, roundWinners, champion } = this.props;
const { winningPlayers, selected, champ } = this.state;
const semi = roundWinners[0];
const final = roundWinners[1];
const champName = champion.map((item) => item);
const reset =
round !== 4 ? "block__reset__tournament" : "block__reset__new-game";
const newGame = `${round !== 4 ? "Reset" : "New Game?"}`;
const buttonClick = `${selected ? "selected" : "block__player"}`;
return (
<>
<div classname="container__wrapper">
<div className="container__tournament">
{round === 1 ? (
<section className="block__round ">
{pairs.map((item, pairIndex) => (
<div className="pairs" key={pairIndex}>
{item.map((names, itemIndex) => (
<Button
key={itemIndex}
handleClick={(e) => this.handleAddWinners(e, pairIndex, itemIndex)}
label={names}
buttonClass={`${pairIndex}-${itemIndex}` === selected ? '<enterYourBackgroundClass' : buttonClick}
value={names}
/>
))}
</div>
))}
</section>
) : round === 2 ? (
<section className="block__round ">
{semi.map((names, index) => (
<div className="pairs" key={index}>
{names.map((names, index) => (
<Button
key={index}
handleClick={(e) => this.handleAddWinners(e, "value")}
label={names}
buttonClass={buttonClick}
value={names}
/>
))}
</div>
))}
</section>
) : round === 3 ? (
<section className="block__round ">
{final.map((names, index) => (
<div className="pairs" key={index}>
{names.map((names, index) => (
<Button
key={index}
handleClick={(e) => this.handleAddWinners(e, "value")}
label={names}
buttonClass={buttonClick}
value={names}
/>
))}
</div>
))}
</section>
) : (
<section className="block__champion">
<p className="champion__greeting">
Congratulations
<br />
<span className="champion__name">{champName}!</span>
<br /> You've won the whole shebang!
</p>
</section>
)}
<Button
buttonClass={`${
round !== 4 ? "block__next-round" : "button__notActive"
}`}
label={`${round !== 3 ? "Next Round" : "See Winner"}`}
handleClick={this.handleRound}
disabled={disabled}
/>
<Link to={"/"} className={reset}>
<Button
buttonClass={reset}
handleClick={handleClear}
label={newGame}
/>
</Link>
</div>
</div>
</>
);
}
}
export default Matches;

Changing the order of an item in a list using ReactJS

I have created a list using material UI and reactjs, and when a new element is added to the list the new element will go on top of the list.
I have a requirement where when I click on an element on the list the element should be strike-through and that now that element should be listed on the bottom of the list.
I was able to strike-through the element when clicked, but I am confused as to how to bring the element to the bottom of the list
How should I approach this problem?
The code of the listlayout.js is presented here, In this code, the added items are listed, and I need to find the way to change the list order when an element is stricked
app.js
class App extends Component {
constructor(props) {
super(props);
this.state={
items:[],
newItem:{
id:'',
itemText:''
},
updateItem:false
};
this.handleInput = this.handleInput.bind(this);
this.addItem = this.addItem.bind(this);
}
handleInput = e =>{
this.setState({
newItem:{
id:1 + Math.random(),
itemText: e.target.value
}
});
};
addItem = e =>{
e.preventDefault();
const typedItem = this.state.newItem;
if(typedItem.itemText !==""){
const typedItems=[...this.state.items,typedItem];
this.setState({
items:typedItems,
newItem:{
id:'',
itemText: ''
},
updateItem:false
})
}
};
render() {
return (
<div >
<HeaderBar/>
<ListLayout items={this.state.items}
/>
</div>
);
}
}
export default App;
ListLayout.js
const ToDoList = props => {
const clearList = props.clearList;
const deleteItem = props.deleteItem;
const updateItem = props.updateItem;
const strikeList = props.strikeList;
const listItems = item => {
return <div key={item.id}>{item.itemText}</div>;
};
const completed = id => {
document.getElementById(id).style.textDecoration = "line-through";
return true;
};
const strikeTextMethod = id => {
completed(id);
};
return (
<div>
<Grid container justify="center" alignContent="center">
<Grid item xs={12} md={6}>
<Typography variant="h6" className={classes.title}>
To do List
</Typography>
<div className={classes.demo}>
<List dense={dense}>
{items
.slice(0)
.reverse()
.map(x => (
<ListItem
key={x.id}
button
id={x.id}
onClick={() => strikeTextMethod(x.id)}
divider
>
<ListItemText primary={listItems(x)} />
<ListItemSecondaryAction></ListItemSecondaryAction>
</ListItem>
))}
</List>
</div>
</Grid>
</Grid>
<br />
</div>
);
};
export default ToDoList;
You have to mainatain the strike event for each item in the array. You can add an additional property to the array items, like isStriked or status.. something like that.
Then you can sort them accordingly..
Your code doesn't seem to be the entire solution. I don't see the definition of items as an example.
but something like this could be a workaround.
const ToDoList = props => {
const [items, setItems] = React.useState(props.items || []); // Initial values
// Maybe you need to these lines to sync the items state.
React.useEffect(
() => {
setItems(items)
},
[props.items]
)
const completed = id => {
document.getElementById(id).style.textDecoration = "line-through";
return true;
};
const strikeTextMethod = id => {
const index = items.findIndex(x => x.id === id);
const newItems = [items[index], ...items.slice(0, index - 1), ...items.slice(index + 1)]
setItems(newItems);
completed(id);
};
return (
)
}

How to hide all the div while showing the one which is clicked, in React?

I'm generating some identical div through a list. Below is the sample code.
I'm toggling this div
class App extends React.Component {
state = { showKitten: false };
handleToggleKitten = () => {
this.setState((prevState, props) => ({
showKitten: !prevState.showKitten,
}));
};
render() {
return (
<About
data={datalist}
showKitten={this.state.showKitten}
handleToggleKitten={this.handleToggleKitten}
/>
);
}
}
const About = ({ datalist, showKitten, handletogglekitten }) => {
return (
<div>
{datalist.map((item, index) => {
return (
<div key={index}>
<div onClick={handletogglekitten} />
showKitten ? <div /> : null
</div>
);
})}
</div>
);
};
I have defined tooglefunction and the flag state variable in parent and passing them to children and in children component, I'm creating this divs by iterating over a list. Right now I am able to achieve the toggle functionality for the individual div set but I want to hide all the div and show the one which is clicked.
You could use the index value. Here's a working example.
const datalist = ["cat 1", "cat 2", "cat 3"];
class App extends React.Component {
state = { showKittenIndex: null };
render() {
return (
<About
datalist={datalist}
showKittenIndex={this.state.showKittenIndex}
toggleKitten={index => this.setState({ showKittenIndex: index })}
/>
);
}
}
const About = ({ datalist, showKittenIndex, toggleKitten }) => (
<div className="about">
{datalist.map((item, index) => (
<div key={index}>
<button onClick={() => toggleKitten(index)}>toggle {index}</button>
{showKittenIndex === index && <div>{item}</div>}
</div>
))}
</div>
);
I have a very similar approach than #Kunukn.
But I don't see the need to wrap it in a functional component.
import React, { Component } from 'react';
const elements = ['DIV #1', 'DIV #2', 'DIV #3', 'DIV #4', 'DIV #5', 'DIV #6'];
class App extends Component {
constructor(props) {
super(props);
this.state = {
activeElement: null,
allElements: elements,
};
}
render() {
return (
<About
elements={this.state.allElements}
showIndex={this.state.activeElement}
toggleIndex={index => this.setState({ activeElement: index })}
/>
);
}
}
const About = ({ elements, showIndex, toggleIndex }) => (
<div className="about">
{elements.map((element, index) => (
<div key={index}>
<div onClick={() => toggleIndex(index)}>toggleIndex {index}</div>
{showIndex === index && <div>{element}</div>}
</div>
))}
</div>
);
export default App;
I did write a little clickHandler ... I know that it is not needed at the moment, but when you would want to alter the data received with the click-event this could be handled there as well.
EDIT
According to the comment I improved the code a bit by making a functional component showing the DIVs. I did also dismiss the clickHandler() function.

Categories

Resources