Let me explain what I want to achieve: first of all, I'm building a React Application, but I think this is a JavaScript-related "problem".
Basically, what I want is to prevent the user to change page when he has made some changes on a form and he hasn't saved them. For this, let's just pretend we have a variable formIsEdited that is set to true if there are unsaved changes, false otherwise.
I know something similar to this can be achieve with the beforeUnload event, or with The <Prompt> component belonging To React Router, but both don't allow me to have a custom modal: what I want to show it's a div with my own style, my own button, etc, ...
So, I came up with an idea: I put a eventListener on the click event and, if the click is on a link and formIsEdited is true:
- I prevent the default behavior;
- I save in a variable
lastClickthe element clicked; - I show my modal;
- If the user chooses to procede with the change page, i set
formIsEditedto false, I pretend a click on the element saved inlastClickthat will lead to the change page.
Then, it may happens that a whole div is inside an anchor element, so I also need to find the closest anchor element of the div on which the click has been made: if the research of the link doesn't return null, it means that the click would lead me to a link. So, I guessed that e.stopPropagation() would achieve what I wanted, but... it doesn't!
If you look at the snippet code.. I thought that, if you click on the blue box, $(e.target).closest('a'); would find the link to stackOverflow and then, since it's not null, would stop the propagation, therefore would avoid the change page.. But it doesn't work.
Any idea why? Or any idea to achieve what I wanted in the first place?
EDIT: I know there are several other question about preventing the changePage, but this question is more about the reason why stopPropagation does not avoid the click on the anchor element.
One more info: if I would take document.anchors and foreach element add a listener in which I do the action I itemize before, I can prevent the change page, with my own modal and my own logic!
But, unfortunately, since I'm using React, some anchor item are not in the DOM when I can call the function that adds the listener just mentioned.
EDIT2: I tried Luca's solution and, as I remembered, it doesn't work.. But the behavior of React is "strange".
Let me explain: if I use the following code: let anchors = document.getElementsByTagName("a");
for (let i = 0; i < anchors.length; i++) {
anchors[i].addEventListener("click", (e) => {
clickListenerAnchorUnsavedChanges.call(this, e, anchors[i]);
}
}
function clickListenerAnchorUnsavedChanges(this: any, e: any, anchor: any) {
// if Edit has been made
console.log("Inside function1");
e.preventDefault();
}
The things works. Actually, let's pretend I click on the anchor which links to the /Account page: the write inside function1 is printed before the write I've put inside the constructor of the Component Account.
Instead, with the following function:
function test1(this: any) {
window.addEventListener("click", (e) => {
console.log("inside function 2");
// if edits have been made
let closestLink = $(e.target).closest('a');
if (closestLink != null) e.preventDefault();
}
}
It appears that the first thing to be printed is the console.log inside the constructor of Account component, and then inside function 2.
I don't know, it seems that, if I modify directly the behavior of an anchor, I can actually redirect/change the flow of the actions performed by a a click on a link. Instead, by modify the behavior on a click event, I cant.. But it seems that now this fact is more React-related, because in the snippet here the e.preventDefault() works.
window.addEventListener("click", (e) => {
var closestLink = $(e.target).closest('a');
if (closestLink!= null) {
e.preventDefault();
e.stopPropagation();
}
});
#span-1, #span-2 {
display: inline-block;
width: 200px;
height: 100px;
}
#span-1 {
background-color: blue;
}
#span-2 {
background-color: green;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<a href="https://stackoverflow.com/">
<span id="span-1" />
</a>
<span id="span-2">
</span>
</div>