gasparesganga/jquery-loading-overlay

LoadingOverlay iterate many overlays and hide programmatically

Closed this issue · 6 comments

Hi @gasparesganga

question

I would like to iterate over all overlays and hide them programmatically. What I tried below doesn't work for me.

I can call hide and show explicitly and it will work as expected.

I appreciate any assistance or hints you can provide. Thank you for creating such an easy library to use! 👍

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gasparesganga-jquery-loading-overlay@2.1.7/dist/loadingoverlay.min.js"></script>

<img id="scotty" src="https://i.imgflip.com/1pg0vt.jpg" alt="" width="300">

$("body").LoadingOverlay("show", {});
$("#scotty").LoadingOverlay("show", {});

////These work when explicitly called
//$("body").LoadingOverlay("hide", true);
//$("#scotty").LoadingOverlay("hide", true);

//I want to interate over all overlays and hide them programatically. 
//This code will not hide the overlays.
//$(".loadingoverlay").each(()=>{
//    $(this).LoadingOverlay("hide", true);
//});

//edit per suggestion by gasparesganga - does not hide the overlays.
//$(".loadingoverlay").each((i, el)=>{
//    $(el).LoadingOverlay("hide", true);
//    console.log(i, el);
//});

//final solution per suggestion by gasparesganga 
$(".loadingoverlay").each((i, el) => {
    // Each .loadingoverlay element stores some data. You can retrieve it using .data("loadingoverlay_data")
    $(el).data("loadingoverlay_data").container.LoadingOverlay("hide", true);
});

Hi!
I cannot access a computer and try some code, but I think the issue is that arrow function and this: if you use an arrow function it will inherit the one from the parent scope.

Use explicit variables for the .each() iterator:

$(".loadingoverlay").each((i, el)=>{
    $(el).LoadingOverlay("hide", true);
});

NB: I cannot test the code, but you will get the idea, the problem is the context of this in the arrow function ;)

Hi, Thank you for the quick reply! I have edited my original post to include your suggested change. The overlay still does not hide. I also tried the traditional function syntax without success. If you get a chance to advise further, I appreciate your assistance.

$(".loadingoverlay").each(function (i, el){
    $(el).LoadingOverlay("hide", true);
    console.log(i, el);
});

Alright, now I get it. This morning I answered from my phone and I couldn't see your code properly.

What you're trying to achieve is not possible using a $(".loadingoverlay") selector. You need to target the element LoadingOverlay was created for in the first place, in your case $("body") and $("#scotty").
The way you are trying to achieve that is, in my opinion, counterintuitive and not the way the plugin was designed for.
The natural question that comes to my mind is: what are you trying to achieve? There is probably another way to do it.

Having said that, just for the sake of curiosity, is it still possible to do something like what you are suggesting?
Well there is indeed! ;)
It's an hack, meaning it requires a knowledge of the internal mechanism of the plugin and it is not guaranteed to work in future releases, since it is using internal bits that are not meant to be public.

$(".loadingoverlay").each((i, el) => {
    // Each .loadingoverlay element stores some data. You can retrieve it using .data("loadingoverlay_data")
    $(el).data("loadingoverlay_data").container.LoadingOverlay("hide", true);
});

I continued to work on the problem. I discovered upon deeper investigation the same "hack" you mentioned.

I would not want to loose this in future upgrades. Is there a better approach which would be consistent with your upgrade path? I'm open to suggestions.

BTW...I'm using this in an error handler. The overlay is on many elements as data is being loaded.
On error, all overlays are stopped.

Aha, nice find!
Well, it makes sense in an error handler.
I guess a more robust approach would be keeping track of every LoadingOverlay created (actually, a reference to the elements it is called on), or maybe, since it's in an error handler and you hope not to execute that code ever, a catch-all approach:

$("*").each(function (i, el){
    $(el).LoadingOverlay("hide", true);
});

Anyways, I think you can safely use the hack we both found, this behaviour is not going to change anytime soon and especially in v2 branch. I could release a v3 sometime but it would be a complete rewrite with a totally different approach.
My 2 cents, go with the hack and don't worry about it ;)

Thank you greatly for clarifying the questions. I have implemented the "hack" in my codebase as we discussed. I updated my original post with the solution. And will close out this issue. Cheers!