Exclude child components from <div onclick> - html

I render multiple 'div' which the user can select by clicking on it with a simple onClick:
<div onClick={() => this.handleTrackerCardClick()}>
However the user can also edit a field displayed on the 'div' by clicking on a button. In this case I don't want the 'div onClick' to be called, because obviously the user wants to use the Edit function and not to select the 'div'.
See the following example:
The user can click on the green area to select the 'div'
If the pencil (in red area) is clicked, I don't want the call the 'div onClick'
Is this possible?
Thank you!

There are two approaches you can take to this.
Handle it on the div
Test to see if the click was on the edit function
(event) => {
const div = event.currentTarget;
const edit = div.querySelector('.edit');
if (edit === event.target) {
return;
}
return this.handleTrackerCardClick();
}
This code example makes assumptions about the DOM structure. Adjust as needed.
One of the assumptions is that the edit control is a single element with no element children. If it isn't, then you need to test to see if the click was any of the children too. Generally you would recursively check parentNode starting on event.target until you reached a match for div or edit.
Handle it on the edit control
Call the method that stops the event from propagating up the DOM and reaching the div.
(event) => {
event.stopPropagation();
this.do_edit_thing();
}

I would simply place the inner, editable field as a sibling to the "parent". This way you can have a click handler for the outer div and the editable field with no overlap in terms of hierarchy.
Something like this:
function App() {
return (
<div style={{ border: "1px dashed red" }}>
<div onClick={() => console.log("outer clicked")}>Outer click</div>
<span
style={{ border: "1px dashed blue" }}
onClick={() => console.log("inner clicked")}
>
Inner click
</span>
</div>
);
}
Check out a working example here

Related

Jquery change css class from variable

For my site, I code a button allowing to change the css of a class present in a div card. My button is located in the card-footer. Having several cards, I can't / don't think to retrieve the element with an id (as there will be X times the same ID)
In order to circumvent this system, I therefore use a parentElement which goes up to the div card
<div class="card">
<div class="card-body">
<p class="change">Change one</p>
<p class="change">Change two</p>
<p class="change">Change three</p>
</div>
<div class="card-footer">
<i id="updateData">change</i>
</div>
</div>
jQuery($ => {
$('#updateData').click(e => {
var element = e.target.parentElement.parentElement;
$('.change').css('display','none');
});
});
I would like to indicate that only the class "changes" present in my element variable and not all the classes in the page.
I don't know how to add a variable to my ".css" command, do you know how ?
Thanks in advance !
First of all since you will have multiple elements with same id that means that you should not use ID and use class instead. Id is meant to be unique. So yours id="updateData" should become class="updateData". Now you can grab all of those buttons and assign event to all of them instead of just first like you were by using id selector.
$('.updateData').click(e=> {});
Next in order to be able to use clicked element in jQuery way convert from arrow function to regular anonymous function since arrow function overrides this keyword. And now you can use jQuery to hide like
$('.updateData').click(function() {
element = $(this).parent().parent();
element.hide();
});
If you want more precise selection to hide only .change elements use
$('.updateData').click(function() {
element = $(this).parent().parent();
element.find(".change").hide();
});
Not bad, but more efficient, when you have multiple click targets, is delegation:
$(document).on("click", ".updateData", function() { ... });
Also .hide() is convenient, but rather then "change the css of a class" add a class "hidden" or something! In best case the class further describes what the element is. CSS is just on top.

How to trigger click event on a div element and show its neighbour element JQUERY

I have a lot of divs, they are the same but the data are differen(I use variable(array of objs) and for loop) but these details aren't important
<div class="item_wrapper">
<div class="item_wrapper_info">
<div class="left-line"></div>
<div class="subject">1</div> <== click here
</div>
<div class="additional_info"> <== display this block
some text
</div>
</div>
I want to achieve this:
If I click .item_wrapper_info div then I want to show .additional_info div
It should be probably done using this keyword.
If I click . item_wrapper_info block I want to find a div with the class name of . additional_info and make display = flex but I don't know how to trigger exactly its . additional_info div.
Probably I can click on .item_wrapper_info > . subject and then show its next neighbour
SOLUTION:
$(document).ready(() => {
$(".item_wrapper").click(function(){
var index = $(".item_wrapper").index(this); get index of a certain clicked .item_wrapper element on my page
$('.additional_info').eq(index).toggle(); using .eq toggle that certain element
});
})
It works for me
I haven't tested this code. Feel free to test it in a runnable snippet.
$(document).ready(() => {
$(".item_wrapper").click(function () {
var index = $(".item_wrapper").index(this)
$('.additional_info').eq(index).css("display","flex");
});
});

Is there a way to prevent events from slotted elements in the light dom from propagating througth the shadow dom?

The problem
I have a complex element P from a third party library that listen to events triggered by user interaction. I want to write a Web component that contain P in its shadow dom, and using the slot mechanism, I want any element C elements put in W’s light dom to be displayed at some place in P.
My problem is the following : For element C that are interactive, I would like to have events propagating directly to the light dom, without triggering any eventual event listener in P.
What I tried
Instead of directly addint the slot in P herachy,I tried to add the slot in an other element that I created, add this element in P herachy and stop the event propagation when bublling in this element. In term of encapsulation, this element is not a parent of the sloted element from the light dom, but doing so still prevent the events to reach W.
Exemple reporducing the situation
The external lib creating P (P.js) :
export function P(container) {
const superComplexInnerHierachy = document.createElement("div")
superComplexInnerHierachy.textContent = "Some P lib's interactive stuff"
superComplexInnerHierachy.addEventListener(
"click",
() => console.log("I'm the third party P lib, I do stuff on click.")
)
container.append(d1)
const thingsIDo = {
add : (elem) => {
superComplexInnerHierachy.append(elem)
superComplexInnerHierachy.append("More P lib's interactive stuff")
}
}
return thingsIDo
}
The web compenent W that I'm trying to write (W.js):
import {P} from "P.js"
class W extends HTMLElement {
constructor(){
this.attachShadow({mode : "open"})
this.value = "Something else"
// Create the lib stuff in the shadow root
this.p = P(this.shadowRoot)
// Add a slot in P's hierachy to inject an element from the light dom
const slot = document.createElement("slot")
this.p.add(slot)
}
}
customElements.define("w-component", W);
The html snippet where W is used.
<script type="module" src="W.js"></script>
<w-component>
<div name="an_interactive_element_usupecting_of_P">
<input type="button" value="Button A">
<input type="button" value="Button B">
</div>
</w-component>
<script type="text/javascript">
document.querySelector("w-component")
.addEventListener("click", evt => {
console.log(`${evt.target.value} was clicked`)
})
</script>
Behavior
The behavior of the current code
When clicking on A
I'm the third party P lib, I do stuff on click.
Button A was clicked
When clicking on things added by P
I'm the third party P lib, I do stuff on click.
Something else was clicked
What would like to have
When clicking on A
Button A was clicked
When clicking on things added by P
I'm the third party P lib, I do stuff on click.
Something else was clicked
A solution could be to capture the event before it is transmitted to the Shadow DOM, by setting the 3rd parameter of addEventListener() to true.
If you detect that it comes from a slotted element and you can handle it by yourself, call stopPropagation() to prevent its propagation.
document.querySelector("w-component").addEventListener("click", evt => {
console.log(`${evt.target.value} was clicked`)
if ( evt.path.findIndex( elem => elem.localName === "slot" ) !== -1 )
evt.stopPropagation()
}, true )

"document.getElementbyId" isn't working for me

I have a button in my page
<button onclick="document.getElementById('donation').style.visibility='visible'">Support</button>
That I want to have linked to making a hidden div (donation) visible. I'm not sure if the getElementById works with divs, but I couldn't find out either, because when I changed the Id to h1, with a simple color change for style, it didn't work either.
Is there a problem with my button or syntax?
You can still work this with an inline onclick.
Andrei is correct about the id needing to be an individual.
<button onclick="document.getElementById('donation').style.visibility='visible'">Support</button>
<div style="background-color: gray; width: 50px; height: 50px; visibility: hidden;" id="donation"></div>
Technically though, it's better to keep your css and javascript in the head tag or outside of the html.
In order for document.getElementById('donation') to return a DOM element this condition would need to be true
there should be one html element and only one with id="donation" in your page. For example: <div id="donation"></div>
It's possible that your function works flawlessly (you can easily tell if it is by looking at your browser console after you pushed the button) but your element would still remain not visible. For example, if its display property is set to none. There are many possible reasons why an element might not be rendered by the browser. The fastest way to pinpoint the reason would be for you to create a minimal, complete and verifiable example (using the <> button) where we could experience the issue.
For me, I think separating the codes will keep things clearer and readable.
<button id="donation_btn">Support</button>
The javascript
function enableDonation( button, donationElement ) {
// check if the button is defined
if ( button != undefined
&& button != null ) {
button.addEventListener( "click", function () {
donationElement.style.display = "block";
});
}
// execute the code on document load
window.addEventListener( "load", function () {
enableDonation(
document.getElementById( "donation_btn" ),
document.getElementById( "donation" )
);
});

How to replace one child react/html component with another based up on event using react?

I am new to react and I have a react component structure like:
<MainComponent>
<Button />
<Content />
</MainComponent>
Now when I click on the Button, I need to replace the existing div (say div1) of the Content component with another div (div2). Can you please tell me how to do it. Thank you.
Note: Till now, on click event I have been changing the data of the single div using state and prop. Now I got to replace the whole div with another one.
Like this.
render() {
var returnIt;
if (useDivOne) returnIt = (<div id='one'></div>);
else returnIt = (<div id='two'></div>);
return (returnItj);
}
If this is your structure:
<MainComponent>
<Button />
<Content />
</MainComponent>
and Content renders something like:
<div>
this is div 1
</div>
I would think you would need to pass a prop to Content that would tell you which div to render, then in Content's Render you manipulate the properties of Boolean logic to present a different component:
class Content extends Component {
render() {
return(
{
!this.props.RenderDiv2Bool &&
<div>
This is Div1 and it will be rendered
because RednerDiv2Bool is false.
</div>
}
{
this.props.renderDiv2Bool &&
<div>
This is Div2 and it will be rendered
because RednerDiv2Bool is true.
</div>
}
)
};
}
Not necessarily better but just another way to do it.