XF 2.2 How to load template in overlay

FoxSecrets

Active member
When I try to load a template in the overlay it doesn't work, but when I open the url directly it works.

How to correctly load a template in overlay? Can someone give me a light?

What I've done so far:

LINK:
Code:
<a href="admin.php?my-template" data-xf-click="overlay">See all items</a>

TEMPLATE:
Code:
<xf:title>My Title</xf:title>

<div class="my-div"></div>

<script type="text/javascript">
  function showItems() {
      // code
  }

  showItems()
</script>
 
Solution
The DOMContentLoaded event will have already been fired when the document (original page) was opened, and will not fire again when the overlay is inserted into the document. Ideally you'd just define the showAllFruits function first and have it take fruits as an argument, and then call it after fruits has been loaded (presuming they might be loaded asynchronously in real-world usage):

HTML:
<xf:title>Test</xf:title>

<div class="items"></div>

<xf:js>
  function showAllFruits(fruits) {
    var div = document.querySelector(".items");
    var cols = 4;
    var start = 0;
    var currentCol = 1;

    for (var i = currentCol; i <= cols; i++) {
      var end = Math.ceil((fruits.length / cols) * i);
      var table =...
You'd need to post the actual error and reproducible code. This works fine for me:
HTML:
<xf:js>
    for (let i = 1; i <= 5; i++) {
        alert(i);
    }
</xf:js>

Also for anything but the simplest cases it's likely best to place the JS in a file (ie. js/some/file.js) and do:
HTML:
<xf:js src="some/file.js" />
 
Yep. Are you actually getting an error, or is the syntax highlighting broken? You can ignore broken syntax highlighting, it misbehaves with embedded JS (at least in <xf:js>) but the template can still be saved without issue.
 
You'd need to post the actual error and reproducible code.

Note that you can't just render a template with a URL (ie admin.php?my-template). Routes are matched to controllers which render templates. The add-on tutorial may be useful for getting a feel for the architecture.
 
I said "new window" wrongly. I meant, the overlay opens, but the template still do not load.

There is no error, even in console, nothing. The javascript do not load in overlay.

And as I said on my first message, if I open the template url directly, it loads normally. The problem is when in overlay.
 
Last edited:
If I paste this into ie. the bottom of navigation_sort:

HTML:
<xf:js>
    for (let i = 1; i <= 5; i++) {
        alert(i);
    }
</xf:js>

And then go click the sort button on the navigation page (which opens in an overlay), the JS is loaded as expected and the overlay is opened.

You'd need to post reproducible code. Also worth noting that overlays are cached by default, so if you've already opened it prior to making changes then you'd need to reload the page to see them.
 
Try this please:

Link:
Code:
<a href="admin.php?my-template" data-xf-click="overlay">See all fruits</a>

my-template:
Code:
<xf:title>Test</xf:title>

<div class="items"></div>

<xf:js>
  var fruits = [
      { code: "APP", name: "Apple"},
      { code: "ORG", name: "Orange"},
      { code: "LIM", name: "Limon"},
      { code: "STR", name: "Strawberry"},
      { code: "BAN", name: "Banana"}
    ];
</xf:js>

<xf:js>
  function showAllFruits() {
    var div = document.querySelector(".items");
    var cols = 4;
    var start = 0;
    var currentCol = 1;

    for (var i = currentCol; i <= cols; i++) {
      var end = Math.ceil((fruits.length / cols) * i);
      var table = document.createElement("table");
      var trt = document.createElement("tr");
      var th1 = document.createElement("th");
      var th2 = document.createElement("th");
      th1.innerHTML = "Code";
      th2.innerHTML = "Fruit";
      trt.appendChild(th1);
      trt.appendChild(th2);
      table.appendChild(trt);

      for (var j = start; j < end; j++) {
        var tr = document.createElement("tr");
        var td1 = document.createElement("td");
        var td2 = document.createElement("td");
        td1.innerHTML = fruits[j].code;
        td2.innerHTML = fruits[j].name;
        tr.appendChild(td1);
        tr.appendChild(td2);
        table.appendChild(tr);
      }
      start = end;
      div.appendChild(table);
    }
  }

  document.addEventListener('DOMContentLoaded', showAllFruits);
</xf:js>
 
The DOMContentLoaded event will have already been fired when the document (original page) was opened, and will not fire again when the overlay is inserted into the document. Ideally you'd just define the showAllFruits function first and have it take fruits as an argument, and then call it after fruits has been loaded (presuming they might be loaded asynchronously in real-world usage):

HTML:
<xf:title>Test</xf:title>

<div class="items"></div>

<xf:js>
  function showAllFruits(fruits) {
    var div = document.querySelector(".items");
    var cols = 4;
    var start = 0;
    var currentCol = 1;

    for (var i = currentCol; i <= cols; i++) {
      var end = Math.ceil((fruits.length / cols) * i);
      var table = document.createElement("table");
      var trt = document.createElement("tr");
      var th1 = document.createElement("th");
      var th2 = document.createElement("th");
      th1.innerHTML = "Code";
      th2.innerHTML = "Fruit";
      trt.appendChild(th1);
      trt.appendChild(th2);
      table.appendChild(trt);

      for (var j = start; j < end; j++) {
        var tr = document.createElement("tr");
        var td1 = document.createElement("td");
        var td2 = document.createElement("td");
        td1.innerHTML = fruits[j].code;
        td2.innerHTML = fruits[j].name;
        tr.appendChild(td1);
        tr.appendChild(td2);
        table.appendChild(tr);
      }
      start = end;
      div.appendChild(table);
    }
  }

  var fruits = [
      { code: "APP", name: "Apple"},
      { code: "ORG", name: "Orange"},
      { code: "LIM", name: "Limon"},
      { code: "STR", name: "Strawberry"},
      { code: "BAN", name: "Banana"}
  ];
  showAllFruits(fruits);
</xf:js>

This would allow you to do something like:

JavaScript:
const res = await fetch(...);
const fruits = await res.json();
showAllFruits(fruits);
 
Solution
Top Bottom