Retrieve Id of a React.js element - javascript

I have set a static id to react element and onClick listener is set to the component, I pass the event object as the param to the listener function and event.target.id is an empty string, how do I get the id of the clicked element?
If I didn't call event.persist(), I am getting all values null, why is it so?
sendDisplayType = (event) => {
event.persist();
console.log(event);
}
<div id="mission" onClick={this.sendDisplayType} className="col l8 m6 left-align nopaddingleft white-space greentext">
<h5> <b>Our Mission</b></h5>
</div>

the event generated is not dom event, it is react event, you should set ref on the div tag to get access to its values including id.

If I didn't call event.persist(), I am getting all values null, why is it so?
All properties will be nullified after the event callback has been invoked. This is for performance reasons.Reference for event pooling
To get an id, what I usually do is just do a classic document.getElementById('id').
But if you really want to go the event way without calling a function on the event prop, what you can do is pass the id as data
so:
<div id="mission" data-id="mission" onClick={this.sendDisplayType} className="col l8 m6 left-align nopaddingleft white-space greentext">
<h5> <b>Our Mission</b></h5>
</div>
Then get it as:
sendDisplayType = (event) => {
event.persist();
console.log(event.target.getAttribute('data-id'));
}
I strongly recommend the code above compare on adding an arrow function like:
<div id="mission" onClick={() => this.sendDisplayType('mission')} />
I don't usually use the code above (calling a function on prop) because of optimization (so if you have a performance issue, optimize as much as possible) - React docs explaining this

Related

Vue3: How to receive #click event on parent DOM?

I have following structure in Vue3 template:
template:
/*html*/
`<div class='element1' #click='onClick'>
<img :src='image_url' />
<p>{{desc_text}}</p>
</div>`,
data() {
return {
image_url: "path/to/image",
desc_text: "Some text goes here"
}
},
methods: {
onClick(e) {
console.log(e);
}
}
Depending on where I click, console outputs e.target to be either <img>, <p> or <div class='element1'>, and it will have e.path set to array of elements, from the element that was topmost under the pointer to the bottom-most, while currentTarget is set to null.
I am looking for a solution where event handler would be called with e.target that points to the element that has #click listener added, in this case, <div class='element1'>. Not to point to any of it's children.
I've been looking at Vue3 documentation on the event bubbles, but so far no modifiers fit my need.
For example #click.self will only fire if e.target is the element that has the event listener, however, if pointer was above any of it's children, it will not fire.
Right now, I use pointer-events: none; styling on all children elements I don't want to have their own pointer event handling, which appears to have sufficient coverage. However, I'm surprised if Vue does not have any option on it's own to handle this case, maybe I am missing it?
I've read through Vue3 Event Modifiers document, but no option listed there does this.
In some cases, I have dozen of sub-elements in an element (eg. a card showing image, title, paragraph etc.), and I'd like entire element to be one big button to click on, with just one #click event handler set.
You can achieve same result (maybe better) without using event target but by passing arguments to the onClick handler.
What I usually do when rendering clickable list is that I pass the entire item
<div v-for="element in elements" :key="'element' + item.id" class="'element' + element.id" #click="onClick(element)">
<img :src='element.image_url' />
<p>{{element.desc_text}}</p>
</div>
It then become easy to handle the onclick as you already have the element you want at your disposal
onClick(element) {
console.log(element);
}

How to add a onclick event on an element with custom input for the function

So i have a HTML element and i have a lot of them but i am only showing one because it is easier the only difference between them is the number in the id <div class="block" id="block0"></div>
and i want to give it a onclick with a javascript so i get this
<div class="block" id="block0" onclick="blockClicked(0)"></div>
and what i mean by custom input i what the input for the function to be the id of the div or just the number in the id. what i mean is that if i have another element with the id of block1 the onclick should be onclick="blockClicked(1)". but all pages i've found so far only shows how to give it a function with a input that is the same everytime. This might have already been answered if it has i couldn't find it.
You should select all your block elements with querySelectorAll() and loop over them with a forEach() method. For each block listen for the click event with addEventListener(). When the click event happens you'll want to figure out which element was clicked and get the id property of that element.
This way you can add more data in the form of data attributes to your block element and read the data from the onBlockClick function with the dataset property on the block element.
// Select all block elements.
const blocks = document.querySelectorAll('.block');
// Is called when a block is clicked.
const onBlockClick = event => {
const { currentTarget } = event; // currentTarget is element we are listening to, so the block element.
const { id } = currentTarget; // Get the id from the block element.
console.log(id); // Now you have an id variable which you can do something with.
});
// Loop over each block and listen for the click event.
blocks.forEach(block => {
block.addEventListener('click', onBlockClick);
});
Try this :
const block = document.getElementById('block0')
block.addEventListener('click',(mouseEvent) => { /* whatever you want to do on click */
blockClicked(0) })
If you want you can loop through all your elements and add them an event listener if they do have the same behavior
const elements = [...document.getElementsByClass('block')]
elements.foreach((el,i) => {
el.addEventListener('click',
mouseEvent => {
/* your event managment */
blockClicked(i)
})
})
Check this link to learn more : https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
You can use this to access the element the handler is bound to and therefore you can use this.id to access it's ID.
While binding event handlers with addEventListener is better overall, the minimal changes to your current code would be something like:
<div
class="block"
id="block0"
onclick="blockClicked(Number(this.id.replace('block')))">
</div>
No matter the way you choose, something to consider is to not use id just for piggybacking data, but use a data-* property instead:
<div
class="block"
data-id="0"
onclick="blockClicked(Number(this.dataset.id))">
</div>

Listening to $emit in vue js and use value in a handler along with parent's value [duplicate]

I have a list of objects within a v-for loop:
<div v-for="(element, index) in myArray">
<child #event-fired="handleEvent(index, dataFromChild)"></child>
</div>
Now I want once the event is fired from the child component, on my handleEvent method, pass the index and the data from the child component.
But now, if I do something like stated above,I get an error on console stating, property or method dataFromChild is not defined....
You can bind an arrow function expression in your event handler. For example
<child #event-fired="dataFromChild => handleEvent(index, dataFromChild)"/>
JSFiddle demo (from the Vue boilerplate) ~ https://jsfiddle.net/zmxksv35/
You can pass the event and the index in the event listener.
<child #event-fired="handleEvent($event,index)"/>
Just pass everything into your event handler as a single object.
<div v-for="(element, index) in myArray">
<child #event-fired="data => handleEvent({ index, data })"></child>
</div>
Then, in your event handler, you can destructure it:
handleEvent({ index, data }) {
// handle the event
}

Get data of specific node element on click

I'm trying to get specific data depending on which node element the user is clicking. I have 4 elements that I have targeted using the querySelectorAll code. What I want to accomplish is that if I click the first element I will console.log that specific data, and if I select the third element I will get that data logged. I've tried a couple of things, but haven't got it to work yet.
function selectedSplit() {
var macroSplits = document.querySelectorAll(".card");
console.log(macroSplits[0].childNodes[3].childNodes[1].innerHTML);
}
It's unclear where you are using selectedSplit - Wether or not it is being used as the event listener return function. But using an onClick event listener, you're return function will be passed the information you need.
If you want to accomplish this in the markup, you could do -
<div class='card' onClick="selectedSplit"></div>
Then you can simply access it via event.target
function selectedSplit(event) {
var thisCard=event.target;
console.log(thisCard.innerHTML);
}
event.target has the clicked element:
d.onclick = e => console.log(e.target)
<div id=d>
<button><b>b</b></button>
<button><i>i</i></button>
<button><u>u</u></button>
<button><s>s</s></button>
</div>

React onClick event on component

I have a React component called <SensorList /> that has many child <SensorItem />s (another React component). I want to be able to declare an onClick event on each <SensorItem /> from within <SensorList />. I have tried doing the following:
sensorSelected: function(sensor) {
console.log('Clicked!');
},
render: function() {
var nodes = this.state.sensors.map(function(sensor) {
return (
<SensorItem onClick={ this.sensorSelected } />
);
}.bind(this));
return (
<div className="sensor-list">
{ nodes }
</div>
);
}
Needless to say, I do not get any "Clicked!" coming up in my console. The React inspector in Chrome indicates that an onClick event is registered, with the above function body as it should be.
I conclude, therefore, that I can't register onClick events on the actual <SensorItem /> tags (I'm not sure why this is, however). How do I go about achieving this otherwise?
This depends on your SensorItem component's definition.
Because SensorItem isn't a native DOM element but, like you said, another React component, onClick as defined here is simply a property of that component. What you need to do is, inside of the SensorItem component pass the onClick prop to an DOM component's onClick event:
var SensorItem = React.createClass({
render: function() {
return (
<div className="SensorItem" onClick={this.props.onClick}>
...
</div>
);
}
});
Problem
The problem, as being explained in another answer, is that onClick on a <SensorItem> React component (contrary to native DOM element like <div> or <p>) is treated as passing of component property, and not of a DOM event handler. And as most likely your <SensorItem> component doesn't declare onClick property, that property value simply gets lost.
Solution
The most straightforward solution is to add onClick property explicitly on SensorItem component, then pass it to the root DOM element of that component:
function SensorItem({ prop1, prop2, onClick }) {
(...)
return (
<p onClick={onClick}>
(...)
</p>
);
}
But the solution that usually works best for me is to group all the undefined component's properties using object destructuring notation, then pass them all to the root DOM element within that component. This way you can pass onClick, onHover, className etc. without needing to define separate properties for each one of them:
function SensorItem({ prop1, prop2, ...rootDOMAttributes }) {
(...)
return (
<p {...rootDOMAttributes}>
(...)
</p>
);
}
No matter which of the two approaches you use, the handler will now work, as it'll now be attached to the root DOM element of SensorItem:
<SensorItem onClick={...} />

Categories