Hide element onClick React based on Id - javascript

I have a list of 3 filters that will show based on their id, when clicked it will show the filters matching the id but I would like to hide it if clicked again. So if Filter 1 is clicked it should show and then if clicked again it should hide
https://www.webpackbin.com/bins/-KpFE0uZN94N_RY2lavn
import React, { Component } from 'react'
export default class Catalogue extends Component {
constructor(props) {
super(props)
this.state = {
filterListShow: false,
active: false
}
this.handleShowFilterList = this.handleShowFilterList.bind(this)
}
// Show Filter checklist onClick
handleShowFilterList(id) {
this.setState({
filterListShow: id,
active: false })
}
render() {
const { filterListShow } = this.state
let test = ''
if (filterListShow === 1) {
test = (<div>show 1</div>)
}
else if (filterListShow === 2) {
test = (<div>show 2{console.log(2)}</div>)
}
else if (filterListShow === 3) {
test = (<div>show 3{console.log(3)}</div>)
}
return (
<div >
<div onClick={()=> this.handleShowFilterList(1)}>
Show Filter 1
</div>
<div onClick={()=> this.handleShowFilterList(2)}>
Show Filter 2
</div>
<div onClick={()=> this.handleShowFilterList(3)}>
Show Filter 3
</div>
{test}
</div>
)
}
}

Just add another check in the onClick handler to check whether the current state is the same as the id of the element clicked,
// Show Filter checklist onClick
handleShowFilterList(id) {
if(this.state.filterListShow !== id) {
this.setState({
filterListShow: id,
active: false })
} else {
this.setState({filterListShow: false})
}
}
DEMO

Simply put the condition in handleShowFilterList function, if same item has been clicked again then reset the state value of filterListShow variable.
Like this:
handleShowFilterList(id) {
this.setState(prevState => ({
//if same then reset otherwise assign new id
filterListShow: prevState.filterListShow == id ? false : id,
active: false
}))
}
Working Code.

Related

Focus on div and his children react

I am working at a project, in React, class components, which is like this:
A navbar with a dropdown and <section> with more cards. When the dropdown it is open the <section> has a background color which is on top of all other elements. To close the dropdown, you click outside of it.
onMouseEnter each card, more data is displayed(display:none to display:flex), and onMouseLeave each card, the data is hidden (display:flex to dispaly:none).
The problem is that, if the mouse pointer it is on a card, after the dropdown closes, the extra data stays hidden.
This is the <div> which is making troubles:
<div
className={
bla.type === "blla"
? "flex"
: bla.type !== "blla" &&
this.props.showOtherAttr === false
? "hidden"
: "flex"
}>
And this is a fragment of the parrent component:
class Article extends Component {
state = {
showOtherAttr: false,
isFocused: false
};
render() {
const dispalyOtherAttr = () => {
if (this.state.showOtherAttr === false) {
this.setState({
showOtherAttr: true
});
} else if (this.state.isFocused === true){
this.setState({
showOtherAttr: true
})
}
};
const hideOtherAttr = () => {
if (this.state.showOtherAttr === true) {
this.setState({
showOtherAttr: false,
});
}
}
const handleFocus = () => {
this.setState({
isFocused: true
})
}
return (
<div
className="card"
onMouseEnter={(e) => {
dispalyOtherAttr();
this.props.reduxAction
}}
onFocus = {()=>handleFocus()}
onMouseLeave={()=>{hideOtherAttr(); this.props.resetStateReduxAction()}
>
<ComponentWithDiv
showOtherAttr={this.state.showOtherAttr}>
</div>
);
}
}
export default Article
I tried to use onFocus event on card's outer <div> but nothing.
I tried to override CSS class .hidden{display: none} like this:
.card:focus div.hidden {
display: flex
}
and like this:
.card:focus:nth-child(3){
display: flex;
}
I searched in react synthetic events, but there is nothing like "mouseAlreadyHere".
How to make it to display extra data and to call this.props.reduxAction, after I close the dropdown and the mouse it is inside the card?
Thank you very much!

Creating show and hide sections with buttons in reactjs

I have three buttons that when clicking show and individual div but this is done in reactjs
import React, { Component } from 'react';
export class ModeExtended extends Component {
constructor() {
super();
this.busButton = this.busButton.bind(this);
this.trainButton = this.trainButton.bind(this);
this.tramButton = this.tramButton.bind(this);
this.state = {
isHidden: false,
}
}
busButton(){
console.log('Bus Button Was Pressed');
this.setState((prevState) => {
return{
isHidden: !prevState.isHidden
};
});
}
trainButton(){
console.log('Train Button Was Pressed');
this.setState((prevState) => {
return{
isHidden: !prevState.isHidden
};
});
}
tramButton(){
console.log('Tram Button Was Pressed');
this.setState((prevState) => {
return{
isHidden: !prevState.isHidden
};
});
}
render() {
return (
<div>
<h5>Mode Extended</h5>
<button onClick={this.busButton}>Bus</button>
<button onClick={this.trainButton}>Train</button>
<button onClick={this.tramButton}>Tram</button>
{this.state.isHidden && (
<div>
<h6>You can show Bus Data Now....</h6>
</div>
)}
{this.state.isHidden && (
<div>
<h6>You can show Train Data Now....</h6>
</div>
)}
{this.state.isHidden && (
<div>
<h6>You can show Tram Data Now....</h6>
</div>
)}
</div>
)
}
}
export default ModeExtended
When I click any of the buttons it shows all bus, tram and train data - how do I get them to just show one thing at a time and making sure that the other states are closed. I am really missing something here and need a pointer or two or three…
How can I add an ID to make each button open separate from each other and when one is clicked how can I close the rest of the divs - or open state, I am so lost here. Please help me out.
Cheers as always!
Here is a REPL of my code:
You need to have 3 different isHidden properties to control your divs. You can do it like this:
this.state = {
isHiddenBus: false,
isHiddenTrain: false,
isHiddenTram: false,
}
and then in your render like this:
{this.state.isHiddenBus && (
<div>
<h6>You can show Bus Data Now....</h6>
</div>
)}
{this.state.isHiddenTrain && (
<div>
<h6>You can show Train Data Now....</h6>
</div>
)}
{this.state.isHiddenTram && (
<div>
<h6>You can show Tram Data Now....</h6>
</div>
)}
also your buttons have to change to state accordingly to this.
busButton(){
console.log('Bus Button Was Pressed');
this.setState((prevState) => {
return{
isHiddenBus: !prevState.isHiddenBus
isHiddenTram: false
isHiddenTrain: false
};
});
}
trainButton(){
console.log('Train Button Was Pressed');
this.setState((prevState) => {
return{
isHiddenTrain: !prevState.isHiddenTrain
isHiddenBus: false
isHiddenTram: false
};
});
}
tramButton(){
console.log('Tram Button Was Pressed');
this.setState((prevState) => {
return{
isHiddenTram: !prevState.isHiddenTram
isHiddenTrain: false
isHiddenBus: false
};
});
}
you can do somthing like this:
import React, { Component } from 'react';
export class ModeExtended extends Component {
constructor() {
super();
this.state = {
curDivIndex:0,//currently visible div index
// isHidden: false,
}
}
renderDiv=()=>{
switch(this.state.curDivIndex){
case 1:return <div> <h6>You can show Bus Data Now....</h6> </div>
case 2:return <div> <h6>You can show Train Data Now....</h6> </div>
case 3:return <div> <h6>You can show Tram Data Now....</h6> </div>
}
return null
}
setVisibleDiv=(index)=>{
this.setState({curDivIndex:index})
}
render() {
return (
<div>
<h5>Mode Extended</h5>
<button onClick={()=>{this.setVisibleDiv(1)} }>Bus</button>
<button onClick={()=>{this.setVisibleDiv(2)}}>Train</button>
<button onClick={()=>{this.setVisibleDiv(3)}}>Tram</button>
{this.renderDiv()}
</div>
)
}
}
export default ModeExtended
EDIT
you want to have three different buttons, on click of each certain div
needs to be visible.
you can achieve this by maintaining the index of currently visible div.
when user clicks any button you have to set the index of div to be visible
which in the above code is achieved by using setVisibleDiv(index) call.
and you can at rendering time use curDivIndex to decide visible div.
Or you can achieve this by declaring state properties for all case:
this.state = {
hiddenBus: false,
hiddenTrain: false,
hiddenTram: false,
}
providing a name attribute to your buttons like so:
<button name="hiddenBus" onClick={toggleDisplay}>Bus</button>
<button name="hiddenTrain" onClick={toggleDisplay}>Train</button>
<button name="hiddenBus" onClick={toggleDisplay}>Tram</button>
then by defining the toggleDisplay function to toggle their display:
toggleDisplay = (event) => {
event.preventDefault(); // default behavior of a clicked button is to send a form so let's prevent this
const { name } = event.target; // find the clicked button name value
this.setState((prevState => ({
[name]: !prevState[name],
}));
}
Setting[name] enables us to target the state prop via the nameattribute value and update it based on the previous state.
Try this
import React, { Component } from "react";
export default class Create extends Component {
constructor(props) {
super(props);
this.state = {
currentBtn: null
};
}
clickedButton = e => {
this.setState({ currentBtn: e.target.id });
};
showDivElem = () => {
const { currentBtn } = this.state;
switch (currentBtn) {
case "A":
return <div>A</div>;
break;
case "B":
return <div>B</div>;
break;
case "C":
return <div>C</div>;
break;
default:
return <div>ABC</div>;
break;
}
};
render() {
console.log(this.state.currentBtn);
return (
<div>
<button id="A" onClick={e => this.clickedButton(e)}>
A
</button>
<button id="B" onClick={e => this.clickedButton(e)}>
B
</button>
<button id="C" onClick={e => this.clickedButton(e)}>
C
</button>
{this.showDivElem()}
</div>
);
}
}

How can I display dynamic state in react

I create a state dynamically, but I need use this state in my render.
See my issue:
handleChange = (name, checked) => {
this.setState({
[name]: checked,
})
}
So, in my render how can I display my [name] state? (I don't know his name, since it's dynamic)
render(){
console.log(this.state....?)
return(
<p>Hello</p>
)
}
My function handleChange is called when I checked my checbkox. So, if I have 5, 10, 20 checkboxes how can I display my [name] state?
----> UPDATE - FULL CODE <----
I'm using a hover propriety to display my checkbox:
CSS using material ui:
hideCheckbox: {
display: 'none',
},
showCheckbox: {
display: 'initial',
},
My main class:
export class Item extends Component {
state = {
isHovering: true,
checkboxChecked: false,
}
handleGetCardSelected = (id, checked) => {
//Here I set isHovering to display my checkbox
//checkboxChecked is a control variable to always display the checkbox if it's checked
if(checked){
this.setState({
isHovering: !this.state.isHovering,
checkboxChecked: true,
})
} else {
this.setState({
checkboxChecked: false,
})
}
}
handleMouseHover = () => {
if(!this.state.checkboxChecked){
this.setState(this.toggleHoverState);
}
}
toggleHoverState = (state) => {
return {
isHovering: !state.isHovering,
};
}
return(
<div
onMouseEnter={this.handleMouseHover}
onMouseLeave={this.handleMouseHover}
>
<div className={`
${this.state.isHovering && classes.hideCheckbox }
${this.state.checkboxChecked && classes.showCheckbox}
`}>
<CheckBoxCard handleGetCardSelected={this.handleGetCardSelected}/>
</div>
</div>
<div
onMouseEnter={this.handleMouseHover}
onMouseLeave={this.handleMouseHover}
>
<div className={`
${this.state.isHovering && classes.hideCheckbox }
${this.state.checkboxChecked && classes.showCheckbox}
`}>
<CheckBoxCard handleGetCardSelected={this.handleGetCardSelected}/>
</div>
</div>
<div
onMouseEnter={this.handleMouseHover}
onMouseLeave={this.handleMouseHover}
>
<div className={`
${this.state.isHovering && classes.hideCheckbox }
${this.state.checkboxChecked && classes.showCheckbox}
`}>
<CheckBoxCard handleGetCardSelected={this.handleGetCardSelected}/>
</div>
</div>
)
}
My CheckboxCard:
import React from 'react';
import { makeStyles, withStyles } from '#material-ui/core/styles';
import { Checkbox } from '#material-ui/core';
const GreenCheckbox = withStyles({
root: {
color: '#43a04754',
'&$checked': {
color: '#43a047',
},
'&:hover': {
color: '#43a047',
backgroundColor: 'initial',
},
},
checked: {},
})(props => <Checkbox color="default" {...props} />);
export default function CheckBoxCard(props){
const [state, setState] = React.useState({
idItem: false,
});
const handleCheckbox = name => event => {
setState({ ...state, [name]: event.target.checked });
let id = name
let checked = event.target.checked
props.handleGetCardSelected(id, checked)
};
return(
<GreenCheckbox
checked={state.idItem}
onChange={handleCheckbox('idItem')}
value="idItem"
inputProps={{
'aria-label': 'primary checkbox',
}}
/>
);
}
By default, my checkbox is hidden because my state isHovering is true, so the css variable hideCheckbox ('display: none') is set.
If I hover the element, is called handleMouseHover and the checkbox is displayed!
If I checked my checkbox, is set checkboxChecked for true and now I'm always displaying my checkbox! But, if I've two or more elements, all checkbox is displayed, because checkboxChecked is an unique element!
So, my checkboxChecked must be dynamic and per item! In this way, if is checked, only this checkbox will be displayed. The others no!
For first element: ${this.state.checkboxCheckedITEM1 && classes.showCheckbox}
For second element: ${this.state.checkboxCheckedITEM2 && classes.showCheckbox}
For second element: ${this.state.checkboxCheckedITEM3 && classes.showCheckbox}
I update my code in sandbox: https://codesandbox.io/embed/material-demo-16t91?fontsize=14
How can I do that?
So, if I have 5, 10, 20 checkboxes how can I display my [name] state?
I think the smart way to do this is to nest components. Have an abstract parent component, that only renders the child component once the name is available. By using this pattern your problem can be solved.
Check out this helpful article
You can filter your object to get only checked names.
Object.keys(this.state).filter(name => this.state[name]);
If you have a finite list of checkbox component
render() {
return (
<div>
<Checkbox
handleChange={() => this.handleChange('abc', !this.state[abc])}
className={this.state['abc'] ? 'checked-class' : '' }
/>
</div>
)
}
In another situation whereby you render a list of dynamic checkbox.
componentDidMount() {
//Calling API to return dynamic list of checkboxes, and dump them into a state
this.setState({ listOfCheckboxes });
}
Then in your render method, you will be using .map function
render() {
return (
<div>
{
this.state.listOfCheckboxes.map(x => (
<Checkbox
handleChange={() => this.handleChange(x.name, !this.state[x.name]) }
className={this.state[x.name] ? 'checked-class' : '' }
/>))
}
</div>
)
}
By doing so :
this.state[name]
You can look at Object.keys(), but if in future you would need to handle more than one state, iteration does not seem to solve the problem.
You could also give it a prefix [name_${name}]: checked, but would not recommend that at all.
If it is not a problem, use an object and you will have full controll over it.
this.setState({
something: {
name,
checked
},
})

check function is called in child component

I am trying to make a custom dropdown but with custom children component. Within the children custom component, there's an onChange event.
The problem now is whenever I trigger the onChange which is for the checkbox, the dropdown is closed.
https://codesandbox.io/s/lr677jv7l7
Partial code
render() {
const { className, onOpen, children } = this.props
const { openItems, selectedItem } = this.state
return (
<div className={classnames('customDropdown', className)}>
<div tabIndex="1"
onBlur={() => { this.setState({ openItems: false }) }}
onFocus={() => { this.setState({ openItems: true }); onOpen && onOpen() }}>
<button className="btn">
{selectedItem}
</button>
<div className={classnames('items', { 'show': openItems === true, 'hide': openItems === false })}>
{children && children}
</div>
</div>
</div>
)
}
You need to get rid of following line:
onBlur={() => { this.setState({ openItems: false }) }}
It basically says that when your div wrapping the button loses focus (eg when you click the checkbox) it should set the state.openItems variable to false and therefore it closes the dropdown.
Edit:
Check out working example here: https://codesandbox.io/s/jnq2rqwr53.
Basically use onClick instead of blur and then you add click event to your document, so anytime user clicks anywhere on the document it calls your hide method and closes the modal. This way the selected checkbox gets checked, but if you want to dropdown to stay open after the selection you'll need to somehow tell the hide function not to execute if user clicked on the checkbox. I did it using ids and simple condition guard at the beginning of the hide method.
Code looks like this:
Hello.js
import React, { Component } from 'react';
import classnames from 'classnames'
export default class CustomDropdown extends Component {
constructor() {
super()
this.state = {
openItems: false,
selectedItem: 'Please select'
}
this.show = this.show.bind(this);
this.hide = this.hide.bind(this);
}
show() {
this.setState({openItems: true});
document.addEventListener("click", this.hide);
}
hide(e) {
if (e.target.id === "1" || e.target.id === "2") {
return false;
}
this.setState({openItems: false});
document.removeEventListener("click", this.hide);
}
render() {
const { className, onOpen, children } = this.props
const { openItems, selectedItem } = this.state
return (
<div className={classnames('customDropdown', className)}>
<div tabIndex="1">
<button className="btn" onClick={this.show}>
{selectedItem}
</button>
<div className={classnames('items', { 'show': openItems === true, 'hide': openItems === false })}>
{children && children}
</div>
</div>
</div>
)
}
}
index.js
import React, { Component } from 'react';
import { render } from 'react-dom';
import Hello from './Hello';
import './styles.css';
const styles = {
fontFamily: 'sans-serif',
textAlign: 'center'
};
class App extends Component {
constructor() {
super()
}
changeCheckbox = () => {
console.log('something')
}
render(){
return(
<div style={ styles }>
<Hello>
<div>
my checkbox 1
<input type="checkbox" onChange={this.changeCheckbox} id="1" />
</div>
<div>
my checkbox 2
<input type="checkbox" onChange={this.changeCheckbox} id="2" />
</div>
</Hello>
</div>
)
}
}
render(<App />, document.getElementById('root'));

ReactJS: onClick change element

I've just started learning React and have a question.
I want to do the following:
If a user clicks on a paragraph I want to change the element to an input field that has the contents of the paragraph prefilled.
(The end goal is direct editing if the user has certain privileges)
I'm come this far but am totally at a loss.
var AppHeader = React.createClass({
editSlogan : function(){
return (
<input type="text" value={this.props.slogan} onChange={this.saveEdit}/>
)
},
saveEdit : function(){
// ajax to server
},
render: function(){
return (
<header>
<div className="container-fluid">
<div className="row">
<div className="col-md-12">
<h1>{this.props.name}</h1>
<p onClick={this.editSlogan}>{this.props.slogan}</p>
</div>
</div>
</div>
</header>
);
}
});
How can I override the render from the editSlogan function?
If I understand your questions correctly, you want to render a different element in case of an "onClick" event.
This is a great use case for react states.
Take the following example
React.createClass({
getInitialState : function() {
return { showMe : false };
},
onClick : function() {
this.setState({ showMe : true} );
},
render : function() {
if(this.state.showMe) {
return (<div> one div </div>);
} else {
return (<a onClick={this.onClick}> press me </a>);
}
}
})
This will change the components state, and makes React render the div instead of the a-tag. When a components state is altered(using the setState method), React calculates if it needs to rerender itself, and in that case, which parts of the component it needs to rerender.
More about states
https://facebook.github.io/react/docs/interactivity-and-dynamic-uis.html
You can solve it a little bit more clear way:
class EditableLabel extends React.Component {
constructor(props) {
super(props);
this.state = {
text: props.value,
editing: false
};
this.initEditor();
this.edit = this.edit.bind(this);
this.save = this.save.bind(this);
}
initEditor() {
this.editor = <input type="text" defaultValue={this.state.text} onKeyPress={(event) => {
const key = event.which || event.keyCode;
if (key === 13) { //enter key
this.save(event.target.value)
}
}} autoFocus={true}/>;
}
edit() {
this.setState({
text: this.state.text,
editing: true
})
};
save(value) {
this.setState({
text: value,
editing: false
})
};
componentDidUpdate() {
this.initEditor();
}
render() {
return this.state.editing ?
this.editor
: <p onClick={this.edit}>{this.state.text}</p>
}
}
//and use it like <EditableLabel value={"any external value"}/>;

Categories

Resources