How to check the class name of the event target in ReactJS? - javascript

I now have a function handleRightClick(e) which will be called when I right click on the container. Inside the container, there are several Items and I expect the menu will be shown only when I right click one of the Items.
export default class ProjectContainer extends React.Component {
...
handleRightClick(e) {
console.log(e.target.name); // I want to check the event target whether is `Item` Class.
this.refs.rightClickMenu.reShow(e.clientX, e.clientY); // This will open the right click menu.
}
...
render() {
return (
<div style={styles.root} onContextMenu={this.handleRightClick} onClick={this.handleLeftClick}>
<Item /><Item /><Item /><Item /><Item /><Item /><Item />
<RightClickMenuForProjectItem ref='rightClickMenu'/>
</div>
);
}
}
If I console.log(e), I get this in Chrome console:
> Object {dispatchConfig: Object, _targetInst: ReactDOMComponent, _dispatchInstances: ReactDOMComponent, nativeEvent: MouseEvent, type: "contextmenu"…}
This is the class Item:
export default class Item extends React.Component {
render() {
return (
<Card style={styles.card} onClick={this.props.onClick}>
<img style={styles.img}/>
<div style={styles.divInfo}>
<h4 style={styles.title}>{this.props.title}</h4>
<div style={styles.projectType}>{this.props.projectType}</div>
</div>
</Card>
);
}
}
Finally, I will use it to form something like this:
handleRightClick(e) {
if (e.target.className == "Item") {
// Open the right click menu only when I right click one of the Item.
this.refs.rightClickMenu.reShow(e.clientX, e.clientY);
}
}
I want to check the event target whether is Item class. How can I access the class name of the event target?

To access at className an element use e.target.className
Try with this
export default class ProjectContainer extends React.Component {
...
handleRightClick(e) {
// To avoid get wrong class name, use this.
// But if the default context menu come up, without this is OK.
e.stopPropagation()
console.log(e.target.className); // This get the className of the target
this.refs.rightClickMenu.reShow(e.clientX, e.clientY);
}
...
}
This is the same on javascript without lib's
If an empty result is appeared in the console, this means that you haven't set the className of the Item class in the render return. You can change your class to be like this:
const className = 'Item';
export default class Project extends React.Component {
...
render() {
return (
<Card style={styles.card} onClick={this.props.onClick} className={className}>
<img style={styles.img} className={className}/>
<div style={styles.divInfo} className={className}>
<h4 style={styles.title} className={className}>{this.props.title}</h4>
<div style={styles.projectType} className={className}>{this.props.projectType}</div>
</div>
</Card>
);
}
}
Now the resulting handleRightClick(e) should be like this:
handleRightClick(e) {
if (e.target.className == 'Item')
//Show the menu if it is not visible, reShow the menu if it is already visible
this.refs.rightClickMenu.reShow(e.clientX, e.clientY);
else
//Hide the menu
this.refs.rightClickMenu.hide();
}
Result
The menu will be shown when click one of the Item.
The menu will not be shown when click outside the Item.

Related

How to detect if child is clicked on parent click React

I'm using React and I have the following situation.
I have one parent div with onClick event, which takes full width and inside that div I have an image. I want to be able to know where it is clicked. Thus, I want to know if image (child) or div(parent) is clicked.
My code is as follows:
class APP extends React.Component {
constructor(props) {
super(props)
}
render() {
return (
<div className="parent" onClick={(e) => console.log("PARENT CLICK")}>
<img src="https://interactive-examples.mdn.mozilla.net/media/cc0-images/grapefruit-slice-332-332.jpg"
style={{maxWidth: "60%", maxHeight: "90%", pointerEvents: 'none', zIndex: 99999}}
onClick={e => console.log("IMAGE CLICK")}
/>
</div>
)
}
}
ReactDOM.render(<APP />, document.querySelector("#app"))
But it detects always the parent click. I tried to add z-index to the child, but I think that child can't be in front of parent.
Here is the fiddle.
class APP extends React.Component {
constructor(props) {
super(props)
}
handleclick(e){
e.stopPropagation();
console.log(e.target.tagName);
return false;
}
render() {
return (
<div className="parent" onClick={(e) => this.handleclick(e)}>
<img src="https://interactive-examples.mdn.mozilla.net/media/cc0-images/grapefruit-slice-332-332.jpg"
style={{maxWidth: "30%", maxHeight: "30%", zIndex: 99999}}
onClick={(e) => this.handleclick(e)}
/>
</div>
)
}
}
ReactDOM.render(<APP />, document.querySelector("#app"))
please note here I added e.stopPropagation() in the click event which only executes with the target element.. here you can read more about propogation
and also please remove the CSS pointerEvents: 'none' from the img tag, it works fine.
Working Fiddle
pointerEvents : none will block the pointer events.Remove that from your styling
You have pointerEvents set to none in your img's inline style object. Remove that. Can remove zIndex as well.
From CSS-Tricks:-
pointer-events:none prevents all click, state and cursor options on
the specified HTML element
You don't need e.stopPropagation() here. Just set the event handler only on parent like so (this is known as event delegation) :-
class APP extends React.Component {
constructor(props) {
super(props)
}
handleclick(e){
console.log(e.target.tagName);
}
render() {
return (
<div className="parent" onClick={this.handleclick}>
<img src="https://interactive-examples.mdn.mozilla.net/media/cc0-images/grapefruit-slice-332-332.jpg"
style={{maxWidth: "30%", maxHeight: "30%"}}
/>
</div>
)
}
}
ReactDOM.render(<APP />, document.querySelector("#app"))
Im not sure if this is the react way of doing this but in javascript you can use the event object properties to get the element that triggered it with event.target and the element that handled it with event.currentTarget.
document.querySelector('#parent').addEventListener('click', (e) => {
console.log(`clicked element is: ${e.target.id}`);
console.log(`event handler element is: ${e.currentTarget.id}`);
});
<div id='parent'>parent
<div id='child'>child</div>
</div>
As CodeBug noted above it should be enough to stop the propagation on the click event by calling (inside of the onClick function):
event.stopPropagation();

Reactjs - Toggle dropdown menu on click outside anywhere on page instead of just click on the icon

I have a React js App (No JQuery please) drop down menu that I trigger when the ▼ character is clicked. With my code below, the dropdown menu disappears only when the same ▼ is clicked again. I want to make it disappear when the user clicks anywhere else on the page. How to change the code below to make the dropdown menu disappear when the user clicks anywhere else on the page as well and not just by clicking the same icon ▼ ?
Toggler Icon:
<span className="show_more" onClick={this.toggleOptions}>
<MaterialIcon icon="keyboard_arrow_down" />
</span>
Code for toggling: (used by many components so can the fix be only here ?)
import React, { Component } from 'react'
...
import MaterialIcon from '../icons/material-icon'
import HeaderLogo from './logo'
export default class Header extends Component {
state = {
showOptions: false,
}
toggleOptions = () => this.setState({ showOptions: !this.state.showOptions })
render() {
let { showOptions } = this.state
return (
<div className="header">
<div className="row-container container">
<div className="col-l">
<HeaderLogo />
</div>
<div className="col-m">
<Search />
</div>
<div className="col-r">
<div className="header_right">
<HeaderTopLinks />
<span className="show_more" onClick={this.toggleOptions}>
<MaterialIcon icon="keyboard_arrow_down" />
</span>
</div>
{showOptions ? (
<HeaderOptions toggleOptions={this.toggleOptions} />
) : null}
</div>
</div>
</div>
)
}
}
The answer can be found here
But to sum it up, you have to listen for clicks on the document, and write a function that will walk the tree and tell you if the click occurred inside or outside your component
Here are the important bits from that link to add to your component:
handleClickOutside(event) {
if (this.wrapperRef && !this.wrapperRef.contains(event.target)) {
alert('You clicked outside of me!');
this.setState({ showOptions: false });
}
}
componentDidMount() {
document.addEventListener('mousedown', this.handleClickOutside);
}
componentWillUnmount() {
document.removeEventListener('mousedown', this.handleClickOutside);
}
render() {
let { showOptions } = this.state;
return <div className="header" ref={(node) => this.setWrapperRef = node}>...all the rest of the component goes here...</div>;
}
For the record, there are many ways of accomplishing this, this is just one approach.

How to call parent function in child component

I checked quite a lot of examples but found most of them having events fired in Child Component.
Can someone please suggest how can I call the Parent Component's function in child with the click event on Parent Component? Thanks.
Parent Component (app.js):
Class App extends Component {
handleClick = (e, id, text) => {
e.preventDefault();
this.setState({val: text})
}
render() {
return (
<div>
<Form val={this.state.val} Click={this.handleClick.bind(this) }/>
<Button onClick={(e) => this.handleClick(e, todo.id, todo.text)}>
<Icon>edit_icon</Icon>
</Button>
</div>
)
}
}
Child Component (form.js):
this.props.Click(); //where should i call this function since my button is in parent component
Class Form extends Component{
render() {
const { text } = this.state;
return (
<TextField
value={text}
color="secondary"
/>
)
}
}
}
If you want to call it in your Child component, you need an event to trigger it or maybe a condition. So, for example in your form.js, we will trigger it with a button click form your child component
render() {
const { text } = this.state;
return (
<TextField
value={text}
color="secondary"
/>
<Button onClick={this.props.Click} />
)
}
}
Maybe, using a Button in your child component is not a great choice for your case since you already have a Button to call the Click function in your parent component, this Button in child component I made is only for example
One way you can do this is use a ref to call the function..
// create the ref
constructor() {
super();
this.myFormRef = React.createRef()
}
// click handler for the button
handleClick = (e, id, text) => {
// here you have the child instance which gives you access to its functions
this.myFormRef.someChildMethodThatIsOnTheChildClass()
}
render() {
// notice here we use the ref on the form via... ref={this.myFormRef}
return (
<Form val={this.state.val} ref={this.myFormRef} Click={this.handleClick.bind(this) }/>
<Button onClick={(e) => this.handleClick(e, todo.id, todo.text)}>
<Icon>edit_icon</Icon>
</Button>
)
)
I would like to note though that it doesn't seem to make much sense as to why you want to do this. You should probably re-think your architecture. Also what is the button press supposed to be doing? submitting the form?

Toggle class except if a child is clicked in React

I want to have a header where you can click it to hide/show it. But on this header, there will be a group of buttons that would be part of a child element. If you click these buttons, I don't want the whole thing collapse.
How can I achieve this in React? What I have so far is going to collapse everything, because Child is in Parent and under row
class Parent extends Component {
constructor() {
super();
this.state = {
show: false
}
}
render() {
return (
<div className="row" onClick={() => this.setState({show: !this.state.show})}>
<div className="col-2">
<Child/>
</div>
...
</div>
)
}
}
You should be able to use stopPropagation() in the event handler for the buttons to prevent it from bubbling further. See http://facebook.github.io/react/docs/events.html for API details.
class Child extends Component {
handleClick(event) {
event.stopPropagation();
doSomething();
}
render() {
return (
<button onClick={e => this.handleClick(e)}>
Click Me!
</button>
);
}
}
In Child's onClick event handler,
add this line
event.stopPropagation()

React.js: How to append a component on click?

I'm new to React and I'm puzzled on something kind of basic.
I need to append a component to the DOM after the DOM is rendered, on a click event.
My initial attempt is as follows, and it doesn't work. But it's the best thing I've thought to try. (Apologies in advance for mixing jQuery with React.)
ParentComponent = class ParentComponent extends React.Component {
constructor () {
this.addChild = this.addChild.bind(this);
}
addChild (event) {
event.preventDefault();
$("#children-pane").append(<ChildComponent/>);
}
render () {
return (
<div className="card calculator">
<p><a href="#" onClick={this.addChild}>Add Another Child Component</a></p>
<div id="children-pane">
<ChildComponent/>
</div>
</div>
);
}
};
Hopefully it's clear what I need to do, and I hope you can help me attain an appropriate solution.
Don't use jQuery to manipulate the DOM when you're using React. React components should render a representation of what they should look like given a certain state; what DOM that translates to is taken care of by React itself.
What you want to do is store the "state which determines what gets rendered" higher up the chain, and pass it down. If you are rendering n children, that state should be "owned" by whatever contains your component. eg:
class AppComponent extends React.Component {
state = {
numChildren: 0
}
render () {
const children = [];
for (var i = 0; i < this.state.numChildren; i += 1) {
children.push(<ChildComponent key={i} number={i} />);
};
return (
<ParentComponent addChild={this.onAddChild}>
{children}
</ParentComponent>
);
}
onAddChild = () => {
this.setState({
numChildren: this.state.numChildren + 1
});
}
}
const ParentComponent = props => (
<div className="card calculator">
<p><a href="#" onClick={props.addChild}>Add Another Child Component</a></p>
<div id="children-pane">
{props.children}
</div>
</div>
);
const ChildComponent = props => <div>{"I am child " + props.number}</div>;
As #Alex McMillan mentioned, use state to dictate what should be rendered in the dom.
In the example below I have an input field and I want to add a second one when the user clicks the button, the onClick event handler calls handleAddSecondInput( ) which changes inputLinkClicked to true. I am using a ternary operator to check for the truthy state, which renders the second input field
class HealthConditions extends React.Component {
constructor(props) {
super(props);
this.state = {
inputLinkClicked: false
}
}
handleAddSecondInput() {
this.setState({
inputLinkClicked: true
})
}
render() {
return(
<main id="wrapper" className="" data-reset-cookie-tab>
<div id="content" role="main">
<div className="inner-block">
<H1Heading title="Tell us about any disabilities, illnesses or ongoing conditions"/>
<InputField label="Name of condition"
InputType="text"
InputId="id-condition"
InputName="condition"
/>
{
this.state.inputLinkClicked?
<InputField label=""
InputType="text"
InputId="id-condition2"
InputName="condition2"
/>
:
<div></div>
}
<button
type="button"
className="make-button-link"
data-add-button=""
href="#"
onClick={this.handleAddSecondInput}
>
Add a condition
</button>
<FormButton buttonLabel="Next"
handleSubmit={this.handleSubmit}
linkto={
this.state.illnessOrDisability === 'true' ?
"/404"
:
"/add-your-details"
}
/>
<BackLink backLink="/add-your-details" />
</div>
</div>
</main>
);
}
}

Categories