Trying to show modal on page load

i followed a tutorial that created a button and got it working for what it was. it created a button and i was able to trigger the modal by clicking it. however i want this modal to load upon the page loading.

i found another post by @PaulOB and simply pasting that exact code did what i wanted it to, however it obviously wasn’t using my modal. i’m trying to incorporate what worked there into mine, but i can’t seem to figure out how to trigger this upon the page load.

the tutorial i followed used this code:

<script type="text/x-handlebars" data-template-name="modal/custom-modal">
{{#d-modal-body title="custom_modal_title" class="custom-modal"}}
  <h1>Hello World!</h1>
{{/d-modal-body}}
</script>


<script type="text/discourse-plugin" version="0.8.18">
let currentLocale = I18n.currentLocale();
I18n.translations[currentLocale].js.custom_modal_title = "My custom modal";

const showModal = require("discourse/lib/show-modal").default;

api.createWidget("modal-button", {
  tagName: "button.btn.btn-primary",

  html() {
    return "Open Modal";
  },

  click() {
    showModal("customModal");
  }
});
</script>

<script type="text/x-handlebars" data-template-name="/connectors/topic-above-post-stream/modal-button">
{{mount-widget widget="modal-button"}}
</script> 

the code is obviously set up to make a button and trigger the modal when clicking it, however im unsure what to alter to make it trigger on the page load

When the page loads just trigger a click even manually. Given that there is one button on the page with a class of modal-button, that would look like:

const el = document.querySelector('modal-button');
const event = document.createEvent('HTMLEvents');
event.initEvent('click', true, false);
el.dispatchEvent(event);

P.S. Moved this to the JavaScript forum.

@James_Hibbard that doesn’t seem to do the trick unless i’m adding it incorrectly:

<script type="text/javascript">
    const el = document.querySelector('modal-button');
    const event = document.createEvent('HTMLEvents');
    event.initEvent('click', true, false);
    el.dispatchEvent(event);
</script>

i’m not getting any errors, it’s just not doing anything

Looks right, apart from the fact that you don’t need the type attribute on the script tag.

A couple of questions:

  • What browser are you using?
  • Where have you placed the JavaScript on the page? It needs to run after the button and modal have been added to the DOM.
  • Are there any errors in the console?

If that doesn’t help, could you share a link to a page where I can see this in action?

@James_Hibbard

  1. safari on macos
  2. it is at the end (after all of the code in the first post)
  3. no errors showing

before we get too invested in this, is there a way to do this without a button? i only used that as a starting point; i don’t actually want a button on the page; just for it to show upon loading. is there a way to somehow apply the code in the “another post” link in the first post to this scenario? it seems to just call $(‘name’).modal(‘show’) but that doesnt work here, nor does trying to simply call showModal(“name”) like it does inside click(). (obviously replacing “name” with the actual name)

Yeah man, should be possible without a button, you’d just need to expose a showModal method to the page somehow.

Could you post the HTML generated by the handlebars snippet you posted above?

i can’t say that I’ve done that before. how do i go about finding that info for you? inspect element somewhere?

AFAIK, this will need to be done as a Discourse plugin or a theme / theme component.

Hmm, I guess I missed seeing that one. which tutorial is it?

@Mittineague that can be found here. i originally tried putting the link in the original post but i got hit with a link restriction message so i couldn’t

1 Like

Well, Johani is a member of the CDCK team and he has experience working with theming so I trust that post from last October is accurate for what it does.

Modals can be a bit obtrusive unless users take active steps to initiate them, so having a modal display on a page load event isn’t something I’ve looked into doing. I don’t know of any “page load modal” tutorials but I think if you look at the code for other “on page load” themes / theme components there’s a good chance you will be able to figure out how. eg. github repo source code

@Mittineague the code in the “another post” hyperlink in the first post does load it on the page load. my question here is trying to see if i can somehow apply what was done there, to this scenario

I would say the “it” is a widget that can load a modal. Unfortunately there doesn’t seem to be an existing “modal widget”

https://github.com/discourse/discourse/tree/master/app/assets/javascripts/discourse/widgets

AFAIK, custom widgets are possible, but I think it would be easier to use one that’s already there to use. Does this have to be a modal? Can you use an existing widget instead? Depending on what your use case is, maybe using category permissions or a banner would be adequate.

@Mittineague i would definitely prefer a modal. and yeah i was able to get something to pop up when the page loaded using that other custom code, but ideally i would get a modal with my theme to load. if this isnt possible, maybe we can go back to what @James_Hibbard mentioned earlier and simulating the button click when the page loads? wasnt able to get that working either

Hi there heyitsjosh2822,

have you considered using a CSS Modal Window ?

You can see a fully working example in this attachment…

heyitsjosh2822.zip (51.3 KB)

coothead

1 Like

The problem with using the load event is that the widget is added after the load event so by the time the widget is there it’s listening for an event that has already happened and it’s too late.

I think the easiest - but hacky - way would be to use setTimeout instead of click.

Or setInterval to check for the presence of the DOM element, which is cancelled once the button shows up.

Sorry for the brief reply. I’m on the hop.

1 Like

@Mittineague @James_Hibbard this worked! setting the timeout triggers it. i wonder why it doesn’t work when i straight up try to call it?

anyway, if y’all have some extra time, i have two final issues on this topic.

  1. my discourse site is set up so that login is required. is there a way to make this only pop up if a user is logged in, as opposed to also when they are not? currently it shows the “An account is required. Please create an account or log in to continue.” message, but the modal pops up in front of it

  2. i don’t want this to pop up every time the user loads the site. is there a way to implement cookies here? i replaced the timeout code (that works) and put it inside a statement like this:

if (!Cookies.get("popup")) {
    setTimeout(function() { showModal("myModal"); }) // the code that worked on its own
    Cookies.set('popup', 'popped');
}

but it doesn’t seem to work

It’s most likely a timing issue. Calling setTimeout without a delay will run whatever callback function you pass it when the current stack has been cleared. This gives the code that the callback function relies on (the implementation of the showModal method here) chance to run first and be available.

This might be a little trickier. When a user is logged in, Discourse creates a user_signed_in cookie. You could try checking for the presence of that before displaying the modal. Not sure how well that’ll work, though.

That’s easier. This article is a little old, but demonstrates the general principle:

@James_Hibbard i’m having trouble getting these to work… i’m trying to use js-cookie and seems that it isn’t working. i’m doing a basic scenario first before applying it to my situation. am i missing something here? there is no alert coming up at all

<script src="https://cdn.jsdelivr.net/npm/js-cookie@beta/dist/js.cookie.min.js">
if (!Cookies.get("popup")) {
    alert("1"); // first visit
    Cookies.set("popup", "true");
} else {
    alert("2"); // not first visit
}
</script>

You have to include the library, then add a script block.

<script src="https://cdn.jsdelivr.net/npm/js-cookie@beta/dist/js.cookie.min.js"></script>
<script>
if (!Cookies.get("popup")) {
    alert("1"); // first visit
    Cookies.set("popup", "true");
} else {
    alert("2"); // not first visit
}
</script>