javascriptdiscourse

Discourse Sign Up redirect to URL instead of modal


I've been currently trying to change the landing page of the sign up for user sign ups on my discourse install.

I'm trying to via their admin panel in customization in Edit Html/css specifically in the </head> section, i've also tried putting this in the </body>

For some reason this code is not stopping the default action, or redirecting the user on click

<script>
    var thingy = document.getElementsByClassName("sign-up-button")
    thingy.onclick ="return false;"
    thingy.onclick = function() {
        window.location.href = "https://join.domain.com";
    };
</script>

When I try and do this

<script>
    var thingy = document.getElementsByClassName("sign-up-button");
    console.log(thingy.length);
    console.log(thingy)
    for (var i = 0; i < thingy.length; i++) {
            console.log('print this');
    };
</script>

It shows the length of thingy as 0, but then it procedes to print a html element, but never iterates since the length is 0


Solution

  • 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();