0

I'm using menus, tabstrips, etc. on my HTML page, which needs to be initilized in JavaScript, for example:

<ul class="k-menu">
...some menu items
</ul>
<script type="text/javascript">$('.k-menu').kendoMenu();</script>
// This works without any problem

Now I want to remove the from HTML and put into the separate JS file.

$('ul.k-menu').each((i, menu) => {
        if ($(menu).data('kendoMenu') === undefined) {
            $(menu).kendoMenu();
        }
});

But now, how can I fire kendoMenu immediately after loading the ul element? When I will use the following example, the kendoMenu will be initialized after document will be loaded:

$(document).ready(function() {
    $('ul.k-menu').each((i, menu) => {
        if ($(menu).data('kendoMenu') === undefined) {
            $(menu).kendoMenu();
        }
    });
});

But I don't want wait until entire document will be loaded. I want to run the code after element will be loaded (before loaded entire document).

I tryied to use setTimenout, but I cant be sure, if element is loaded before timout will fire.

setTimeout(() => {
  $('ul.k-menu').each((i, menu) => {
        if ($(menu).data('kendoMenu') === undefined) {
            $(menu).kendoMenu();
        }
    });
}, 100);
  • 1
    Just put your new ` – CertainPerformance Feb 10 '20 at 09:57
  • 1
    You can't use setTimeout for this as the loading time is not static. The only reliable way to do this in an external JS file is to initialise the components after the DOM has loaded. Why is this an issue? The difference will be milliseconds. – Rory McCrossan Feb 10 '20 at 09:58
  • @RoryMcCrossan Depends on the page. If the page is huge - which is uncommon, but possible - then I could see a use for running a script as soon as an element appears, but before the whole page has loaded – CertainPerformance Feb 10 '20 at 10:02
  • @CertainPerformance is correct. If you put the ` – Barmar Feb 10 '20 at 10:04
  • That's correct. However my assumption was that the OP was attempting to create a single external script file, for better separation of concerns and also to enable bundling/minification. – Rory McCrossan Feb 10 '20 at 10:05
  • @CertainPerformance But I want to remove all scripts from html and use a separate html file as an example. – user12871387 Feb 10 '20 at 10:28
  • @RoryMcCrossan Yes, It's truth. I want to eliminate the blink of all elements. Because first is loaded HTML and then after some delay the elements are initialized. – user12871387 Feb 10 '20 at 10:31
  • If you remove *all* ` – CertainPerformance Feb 10 '20 at 10:34
  • @CertainPerformance Sorry for bad explanation. I mean remove all initialization – user12871387 Feb 10 '20 at 10:39
  • The now-deleted answer by thanhdx (which got a downvote for some reason, might have been the reason for deletion) is probably the way to do it then, I'll ping him, if he undeletes you can check it out and maybe accept it – CertainPerformance Feb 10 '20 at 10:42
  • @RoryMcCrossan "...attempting to create a single external script file, for better separation of concerns and also to enable bundling/minification." <- this is the reason, why I want do it. I'm using Webpack to build all of my CSS/JS. But I need to solve problem as I written. – user12871387 Feb 10 '20 at 10:46
  • @user12871387 Did you check out the answer that was posted? I'm pretty sure it solves your problem. If it does, you may consider marking it as Accepted to indicate that the issue is resolved – CertainPerformance Feb 13 '20 at 01:07

1 Answers1

1

AFAIK, there's a way to use MutationObserver
You can detect DOM change on the parent node if any child node added & if the added node is the ul you want, then fire the kendoMenu()

An example:

document.querySelector("button").addEventListener("click", function () {
  document.body.appendChild(document.createElement("span"));
});

var observer = new MutationObserver(function (m) {
  if (m[0].addedNodes[0].nodeName === "SPAN")
    document.querySelector("div").innerHTML += "Change Detected<br>";
});

observer.observe(document.body, {childList: true});
<button>Click</button>
<div></div>

Here's another example, which shows that the MutationObserver callback fires as soon as the DOM loads the element during pageload:

// The other <script> tags are there just to demonstrate that the timing is proper;
// on a large page, the MutationObserver callback will be called as soon as the `ul.k-menu` exists,
// without waiting for the rest of the page to download
<script>
window.addEventListener('DOMContentLoaded', () => {
  console.log('DOMContentLoaded');
});
var observer = new MutationObserver((mutations, observer) => {
  const ul = document.querySelector('ul.k-menu');
  if (!ul) {
    return;
  }
  console.log('MutationObserver callback saw that ul.k-menu was just added to DOM');
  observer.disconnect();
  // call .kendoMenu()...
});

observer.observe(document.body, {childList: true});
</script>
<div>Some other div</div>
<script>console.log('Node just before k-menu added to DOM');</script>
<ul class="k-menu">
  ...some menu items
</ul>
<script>console.log('Node after k-menu added to DOM');</script>
<div>Some other div</div>
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
thanhdx
  • 608
  • 4
  • 16
  • Thank you very much for the example. If I will use the example more times for example for menu, tabs, grids, etc. it won't significantly slow down the DOM loading process? Thx. – user12871387 Feb 16 '20 at 21:18
  • I tried your example, and it's working :-) But it's working inside body. But when I will move the example into the header. it not works, because of course document.body does not exists when I call observer.observe... When I try to use first parameter in observe from document.body to document, observer is not working. How can I move your example and initialize in document head? Thank you very much. – user12871387 Feb 24 '20 at 11:02
  • For the first question, it will slow down the DOM, because of mutations in it. And it also depends on what you do in js. – thanhdx Feb 25 '20 at 04:22
  • Why do you want to apply mutation observe with document head, I think it should be left static, I haven't ever tried that yet. – thanhdx Feb 25 '20 at 04:24
  • I've just found something similar: https://stackoverflow.com/questions/11693618/detect-change-in-document-title-via-javascript. You can try it. – thanhdx Feb 25 '20 at 04:27