1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

Requiring javascript in overlay templates

Discussion in 'XenForo Development Discussions' started by RichardKYA, Sep 4, 2016.

  1. RichardKYA

    RichardKYA Well-Known Member

    Having trouble getting js files to work when used in overlay templates, they work perfectly fine in all other templates, but overlay templates seem to be an issue.

    The scripts work fine in an overlay template if it's not minified and it's added directly in template, but as soon as I require them via xen:require, minified or not minified, boom, it doesn't work.

    I can't get my head round what the issue is, when looking in the console, it appears that the scripts are being loaded in the wrong order, and this continues to happen regardless of what order I actually require them in. BUT even with that said, I can require them in any order in all other templates and it still work perfectly fine, it's just overlay templates that seem to be an issue.

    Anyone have any insight on why this might be happening?

    Thank you in advance :)
    Last edited: Sep 4, 2016
  2. Mike

    Mike XenForo Developer Staff Member

    When scripts are loaded after the page is loaded, they're loaded and run asynchronously. That means they don't have a deterministic order. You'll need to detect whether what you want has loaded and delay your action if needed.
  3. RichardKYA

    RichardKYA Well-Known Member

    I'm not sure how to do that, to explain my issue a bit further:

    script 1 - defines functions, etc.
    script 2 - modifies these functions, etc.

    script 2 keeps being loaded before script 1 when required in overlays, obviously this causes it to "break" because the modified functions have not yet been defined because script 1 has not yet loaded.

    I can only modify script 2 because script 1 is an external source.

    How can I delay script 2 from loading until script 1 has loaded?
  4. CyberAP

    CyberAP Well-Known Member

    Use load event in document: document.addEventListener('load', function() { /*your code*/ });
    One thing to notice: it waits for all resources to be loaded.

    You can try another approach and trigger your custom event in the end of your script. Then use this event in your second script to launch.

    More detailed:

    For script 1
    // All your code
    For script 2
    $(document).one('scriptOneLoaded', function() {
      // All your code
  5. RichardKYA

    RichardKYA Well-Known Member

    Thank you @CyberAP for the suggestions, but I've just tried those and they don't work either :(

    Nothing seems to work when it comes to these damn overlay templates

  6. Nobita.Kun

    Nobita.Kun Well-Known Member

    In the first your file Javascript1. Using this:
    XenForo.loadJs('src_of_js', function() {
         // TODO when the JS loaded
  7. RichardKYA

    RichardKYA Well-Known Member

    Thank you for the suggestion @Nobita.Kun, but unfortunately, script 1 is a 3rd party source, so ideally I don't want to be making any edits to it. Modifications happen in script 2 so that script one doesn't have to be tampered with.

    I didn't think it would be this hard to get some js working in an overlay template, I thought it would work just like any other template lol
  8. Nobita.Kun

    Nobita.Kun Well-Known Member

    I dont say that you edit the third party source. Just put in your javascript file.
    RichardKYA likes this.
  9. RichardKYA

    RichardKYA Well-Known Member

    Sorry, I misunderstood what you meant :rolleyes:

    I have it working now using your example (y)

    At the moment though, it works fine because I know the file directory structure, but when adding the path to the "src_of_js", is there a way to get the path when you don't know what it is?

    For example, someone may have their directory set up like....


    ...and someone else may have...


    Is there a way to have something like:

    var scriptDirectory =  some code here to get directory
    XenForo.loadJs('scriptDirectory + "script-1.js"', function() {
        // TODO when the JS loaded
    Or something to that effect?

    I'm having a look for a solution and it does seem like it is possible, but the methods I have found end up breaking again when used in an overlay.

    Anyway, thank you for all your help guys, after 2 and half days, I think things are finally starting to move forward. Hurray! (y)
    Last edited: Sep 7, 2016
  10. Nobita.Kun

    Nobita.Kun Well-Known Member

    If you want js of each user then bypass it through template. Like this
    <div class="someClass" data-js="js_of_user">...</div>
    Then in your script use this:
    Var externalJs = $('.someClass').data('js');
    XenForo.loadJs(externalJs, ....)
    It is for per user setting.
  11. RichardKYA

    RichardKYA Well-Known Member

    I'm not sure I understand what you mean? What goes in place of "js_of_user"?
  12. cclaerhout

    cclaerhout Well-Known Member

  13. RichardKYA

    RichardKYA Well-Known Member

    OK, I've been making progress on this, but I've now hit another wall, so I need to request some help again...

    To build the path to js file location, I am passing the board url via a hidden input:

    <input type="hidden" name="boardurl" value="{$xenOptions.boardUrl}" />
    ...and then in my js file:

    var boardUrl = $("input[name=boardurl]").val() + "/path/to/js/file.min.js";
    ...I've tried doing the same thing but various ways in my js file, but the result is always the same, which is, immediately after the boardUrl portion, an "undefined" folder is being added, so instead of...


    ...I am getting...


    I've checked in the ACP > Basic Board Information and there is no trailing slash or anything there that shouldn't be, so I have no idea where this "undefined" is coming from or why it is being added :confused:

    Does anyone have any ideas?

    Thank you
  14. Mike

    Mike XenForo Developer Staff Member

    I'm not totally clear on what's happening or what you're needing specifically, but XenForo.canonicalizeUrl() might do what you need without passing things in. Don't use a leading slash on your path though unless it's at the root or your domain.
    RichardKYA likes this.
  15. RichardKYA

    RichardKYA Well-Known Member

    Thank you Mike, that done exactly what I needed (y)
  16. RichardKYA

    RichardKYA Well-Known Member

    Hello again,

    I know this thread is a few months old, but I am still having issues with loading js in overlays.

    I gave up trying to fix the issue for a while because it's not a major bug and I got fed up trying, but this one bug has finally taken it's toll and I think it's time I tried once again to do something about it ;)

    I the advice given above seemed to work as it should, so I didn't notice the new issue for a little while because it only arises when the browser cache has been cleared.

    I am using XenForo.loadJs in a script of mine to make sure that another script is loaded before the wrapped code is executed.

    script-1 defines objects that are modified in script-2 so it must be loaded first. script-1 can not be altered, which is why script-2 exists.

    script-2 pretty much looks like...
    XenForo.loadJs(path/to/script-1, function() {
    /////// SOME CODE HERE ////////
    This works completely fine in all templates that require this js file, unless the template is used for an overlay and the js is not already cached by the browser.

    The highlighted green text is the new found part of the issue.

    It's worth noting that the overlay displays as it should in all scenarios. What I have is a datetime picker that I am using to set dates and times for various functions of my add on and what this issue creates is a failure to display the datetime picker when the input field is selected.

    The issue presents itself as follows:

    1: Cache is cleared
    2: User triggers the overlay
    3: A popup form is displayed
    4: User clicks on datetime input field
    5: Nothing happens
    6: User refreshes page and repeats steps 2-4
    7: Datetime picker is displayed as it should be

    After that, it works as it should every time, until the cache is cleared again.

    I imagine that it has something to do with what Mike said about certain scripts being loaded asynchronously which I think will explain why it doesn't work on first load, but I am still unsure what I can do to fix this bug. I think I remember trying to set timeouts, delays, etc, but none of it worked for me at the time, so I think that's why I gave up in the end.

    Anyway, I know it's not a major bug, but understandably, it is a pain in the bum, any time the picker is used in an overlay, it doesn't display on first attempt, which after a while leads to the before mentioned pain in the bum. I like my bum and I would like it to be pain free, call it a new years resolution if you will, probably my weirdest resolution to date, but hey, but whole or no but at all.

    Does anyone have any ideas on how or what I could add to my script so I can make sure that it works without it needing to be cached first? Or if anything else springs to mind as what could be causing this issue, I'd be glad to hear it.

    Please and thank you

    A Happy New Year To All :)
  17. Mike

    Mike XenForo Developer Staff Member

    If you can create a reduced test case, that might help.

    Otherwise, you would likely need to start debugging. Does your loadJs callback code run as you expect? Is the code from script1 indeed available at that point? (Does it expose any globally accessible values to confirm?)

    It's possible the issue could be within script1 itself. It's very difficult to give any particular courses of action in the abstract.
  18. RichardKYA

    RichardKYA Well-Known Member

    Couldn't find anything obvious in the console or debugger, so I decided to try using setTimeout again and this time, it worked. Which is a bit annoying to be honest, because I can remember trying timeouts for ages when I first posted this thread and they didn't work at all. I can even remember Googling "setTimeout not working" lmao

    I'm thinking maybe that was before Nobita gave me the loadJs solution though, and because that fixed the issue I was having at the time, setting timeouts didn't occur to me as a solution for this smaller, related issue.

    Either way, it's doing the job now.

    Thank you again for your help guys (y)

Share This Page