4

I am designing a mobile website keeping in mind all leading browsers - Safari, Chrome, Dolphin, Opera.

I want to show a "loading" element as and when the page navigates / changes / new page is requested.

I cannot use click event on anchor tags as there are many ones present with preventDefault();.

I tried the following:

$(window).on('beforeunload', function() { ... });

But it does not work in Dolphin or Opera.

Can someone suggest a cross-browser solution?

--

EDIT: I realize I wasn't very clear in asking my question, apologies. I created a fiddle here- http://jsfiddle.net/hiteshpachpor/7dadA/5/ based on the response. The example makes use of event bubbling.

Now here's the problem I am facing. I would be showing that loader ($('.jacket').show();) each time page changes / navigates. But I don't want it to show up if a link is clicked; I want to do other operations on my page instead. Now, adding the $('.jacket').hide(); line in all such actions would totally suffice but it will not be very ideal for scaling reasons.

This is why I was evaluating the 'beforeunload' method, but no luck there as it is not cross-browser compatible.

Any kind suggestions to tackle this issue?

Hitesh
  • 330
  • 1
  • 4
  • 10
  • maybe this post will help you http://stackoverflow.com/questions/7389554/crossbrowser-onbeforeunload – Devima Apr 22 '14 at 10:17
  • @Devima thanks! I've already followed that thread and tried `window.addEventListener("popstate", function(e) { ... });` but somehow it isn't working for me. – Hitesh Apr 22 '14 at 11:59
  • Maybe you could make use of custom events? http://api.jquery.com/trigger/ – Eli Apr 24 '14 at 14:33
  • 1
    @Devima Is this a single page app or is there an actual page load? – mike Apr 25 '14 at 16:52
  • 2
    Why can't you use a click event handler? `preventDefault()` will stop the page from changing on a link click however it does not stop the event from bubbling up the DOM. – Jasper Apr 25 '14 at 17:24
  • @mike - It's a multi-page site. There are actual page loads happening. – Hitesh Apr 25 '14 at 19:42
  • 1
    @Jasper - My initial thought was also the same. But here's my limitation: there are quite a few events which use `preventDefault()`. I may end up adding more later, as the project progresses. If I start accounting for these events / elements manually then it will only make my code very rigid and static. That forced me to evaluate the `onbeforeunload` event in the first place. But it does not appear to be working in majority of mobile browsers. – Hitesh Apr 25 '14 at 19:46
  • 1
    That's why the bounty is for – toesslab Apr 25 '14 at 20:16
  • @pc-shooter I don't think you answered @Jasper's question. Since ```preventDefault``` does not stop the event from bubbling up, you should be able to trap that event at the top of the dom without adding events all over the dom. – Evil Buck Apr 26 '14 at 19:12
  • @EvilBuck I didn't post any answer... – toesslab Apr 26 '14 at 19:25
  • my apologies. I read the wrong name. @Hitesh please see above. – Evil Buck Apr 26 '14 at 19:29
  • @EvilBuck, I did not fully understand what you suggested. Can you demonstrate this to me with the help of an example? – Hitesh Apr 27 '14 at 09:01
  • @Hitesh Check this simple JSFiddle: http://jsfiddle.net/MRH4x/ `preventDefault()` will NOT stop a general `$('a').click()` event from firing. So you should be able to use that event to display your animation. If not, then can you clarify what the problem is? – James Duffy Apr 27 '14 at 10:42
  • @Hitesh Did you see that one? http://stackoverflow.com/questions/15986731/is-there-any-way-to-make-onbeforeunload-work-in-opera – toesslab Apr 27 '14 at 17:12
  • @JamesDuffy thanks for creating a fiddle. I've used it to create my own. Please see the edited question. – Hitesh Apr 30 '14 at 01:43

5 Answers5

2

I think what you are trying to achieve are basic AJAX requests? But you are going about it the wrong way. You could instead, used a div to load in the requested pages and then setup an ajax start handler to display your loading message.

your page markup would look something like

<nav>
  <button data-url="homeURL">Home</button>
  <button data-url="anotherURL">Other</button>
</nav>
<div id="loadhere"></div>

the resulting jquery would be like this:

//on button click
$('nav button').click(function(){
  //set the url 
  url = $(this).attr('data-url');
    //load the page
    $('#loadhere').load(url);
});

//ajax start handler
$(document).ajaxStart(function(){
  $('#loadhere').text('LOADING');
});

here is an example codepen

hope this helps

lukeocom
  • 3,243
  • 3
  • 18
  • 30
  • Sorry, I haven't mentioned AJAX anywhere in my question. It's simple page navigation. – Hitesh Apr 30 '14 at 02:36
  • 1
    I realise that, its just that using AJAX is an easier way to what you're attempting, and is designed for simple page navigation. It's a possible cross-browser solution at any rate... – lukeocom Apr 30 '14 at 02:38
  • 1
    @Hitesh Personally, I find this the best answer. Why not thinking another way, if we see that our idea isn't well realisable – toesslab May 01 '14 at 10:08
  • 1
    @Hitesh - luke's answer is the most appropriate one (I voted it up)... you're trying to control interactions with page navigation within your own environment (show something when you start to get the data, and then hide it and show the page once all data is loaded). This is a classic case to use an AJAX solution, so you should load your pages asynchronously and this will solve your problem. – Etai May 01 '14 at 13:30
  • Although this is a very good solution, I have accepted Evil Buck's answer as it is better suitable in my situation. Thanks for your help, @lukeocom :) – Hitesh May 02 '14 at 12:00
0

You could have a onLoad function in the body element that calls a loading div to appear, then setTimeout to lets say 3 seconds then hide loading div and show all other divs/the rest of body

EDIT: I'm pretty sure this will work on all browsers. I'll attach a code snippet once I get on my computer (on my phone now) ;)

RetroCraft
  • 327
  • 1
  • 2
  • 13
  • Actually, it takes more time to get to a page than the time taken to load the whole DOM once a page has started rendering. So adding 3 seconds of forced "loading" time would unnecessarily make the user experience slower. And BTW, yes this would work on all browsers ;) – Hitesh Apr 27 '14 at 09:03
  • Sorry wasn't really sure what you wanted – RetroCraft Apr 27 '14 at 23:17
0

As was mentioned in the comments. However I prefer event delegation instead of attaching events all over the dom.

// this is your original eventListener which prevents the default action (aka, navigating away)
$('#random-link').click(function(event){
    event.preventDefault();
    $('#result').text('I was clicked from random-link event.')
});

// this would be the delegated listener. It wouldn't have to be all "a" tags 
// that you respond to. It could be any css selector that causes the 
// loading message that you want.
$(window).on('click', 'a', function() {
   alert('I still bubble up.');
});

Update:

Perhaps you should not trigger $('.jacket').show() for "links".

$('.jacket').hide();

$('a:not(.prevent)').click(function() {
    $('.jacket').show();
});

$('.prevent').click(function(event) {
    event.preventDefault();
    $('.jacket').hide();
});
Evil Buck
  • 1,068
  • 7
  • 20
0

There is a jquery mobile widget for this. This is used till version 1.4

  $.mobile.loading( "show", { //show loading image
    text: "Your request is processing. please wait ...",
    textVisible: true,
    theme: "b",
    textonly: false,
  });

For help Jquery Mobile Loader Widget.

Kshitiz
  • 2,673
  • 1
  • 18
  • 24
0

In response to your edit:

You can use event.isDefaultPrevented().

$(function() {
    $('.jacket').hide();

    $('.prevent').click(function(event) {
        event.preventDefault();
    });

    $('a').click(function(event) {
        if (!event.isDefaultPrevented())
            $('.jacket').show();
    });
});

JSFiddle: http://jsfiddle.net/F4uPx/

Caveat: Make sure you assign the $('a').click() event handler after the other event handlers; otherwise it will execute first and will fail since preventDefault() won't have fired yet.

James Duffy
  • 1,387
  • 8
  • 16