Discourse Sign Up redirect to URL instead of modal
The problem appears to be that Discourse uses Ember. Nothing is wrong with Ember as a client-side framework, but it seems to be adding elements to the DOM after your script runs. When the element gets added after your script tries to add an event listener, your script won't do much (as you have discovered).
I looked around at a Discourse web page, and I could see that the button was getting added and removed from the DOM quite often. This is probably because the button is only supposed to appear when the user is at the top of the page.
One tactic is to do something to delay your script — such as async defer
, requestAnimationFrame
, or setTimeout
— so that the element will already be around when your script runs. Since I don't have a standalone page to test with, I can't comment on that.
What I'm going to demonstrate is how to attach an event handler when the element is added to the DOM. In the old days, you would have used mutation events, as shown in most of the answers to this question. Since those events are now deprecated, you must use Mutation Observers (which seem to be fairly well supported).
The MutationObserver.observe()
has two arguments: a target element and an options object. The target element is the element that you listen to mutation events on. From using view-source on the page, it appears that there's not much useful inside the body
to begin with, so we'll go off body
. As for the options object, we're interested in childList
mutations, and subtree
since the button is not a direct descendant of body
.
The callback function (the constructor's only argument) will fire whenever the events happen. This is the point when you should look for the button and attach the click event handler. To keep things clean, you might want to check if the button is actually around and disconnect the MutationObserver if it is. No need to keep attaching the event.
For completeness, I also like to call the function to attach the events immediately, just in case the element happens to be around already.
Note that even though the element gets removed from and added to the DOM when you scroll up and down, you only need to attach the event once. It seems to be the same element so the event listener is still attached.
You also mentioned in a comment something about the modal still showing up after you attached a listener. You can stop that with .stopPropagation()
.
Incidentally, that propagation is somewhat related to why you couldn't do a simple $(window).on('click', '.sign-up-button', ...)
. That works for most dynamically created elements, but in this case, the underlying app is also listening for click events and apparently stops the event from bubbling.
My code is below. I'm using jQuery because I saw it was present on Discourse's pages.
var targetNode = $('body')[0];
var attachEvent = function () {
var $button = $('.sign-up-button');
$button.on('click', function (e) {
e.stopPropagation();
// Do the redirect here
console.log('gotcha');
});
if ($button.length) {
console.log('hit');
observer.disconnect();
}
};
var callback = function() {
console.log('mutation');
attachEvent();
};
var observer = new MutationObserver(callback);
observer.observe(targetNode, { childList: true, subtree: true });
// Just in case...
attachEvent();
getElementsByClassName retruns a collection of zero to many objects. You will want to pick one, loop over them, or use jQuery.
This works if you only want to return the first button. ( thingy[0]. )
<script>
var thingy = document.getElementsByClassName("sign-up-button")
//thingy.onclick ="return false;"
thingy[0].onclick = function() {
window.location.href = "https://www.google.com";
//return false;
};
</script>
The "return false" is not needed as you are replacing the onclick event.
A better option is to give the button an ID and then use getElementById to retrieve it.