Add documentation for presenting server generated error pages #6866

Open
thenewguy opened this Issue Dec 31, 2013 · 7 comments

Projects

None yet

3 participants

@thenewguy

I cannot figure out how to make use of my server generated error pages using jqm.

I am sure this is a common case. I am using jqm to enhance server generated output from django (insert server side framework here). The server already formats a simple error message. I would like to use this content instead of the generic "error loading page" popup that jqm shows.

I.e. for 500 error or other errors jqm does not display the page by default

This is the documentation I've found btw: http://api.jquerymobile.com/pagecontainer/#event-loadfailed

Just having trouble rendering the html that is available in data.xhr.responseText

@thenewguy

Got something pieced together that will get me going. Would be nice if something like this was in the documentation. This could be prettier but it let me see the error page and kept the back button working on a page that posted to itself.

$(document).on("pagecontainerloadfailed", function(event, data) {
            // Let the framework know we're going to handle things.
            event.preventDefault();

            // adjust the url so the back button works
            var url = data.absUrl.replace(/#$/, '') + "#error";

            // Prepare your page structure
            var $page = $("<div data-role='page'></div>");
            var $content = $("<div role='main' class='ui-content'></div>");
            var iframe = document.createElement("iframe");
            iframe.srcdoc = data.xhr.responseText
            $(iframe).attr("frameborder", "0");
            $(iframe).css({
              "position": "absolute",
              "top": "0",
              "bottom": "0",
              "left": "0",
              "right": "0",
              "border": "none",
              "padding": "0",
              "width": "100%",
              "height": "100%",
            });
            $page.append($content);
            $content.append(iframe);


            // Append the new page into pageContainer
            $page.appendTo($.mobile.pageContainer);

            // ... attempt to load some other page ...
            // at some point, either in this callback, or through
            // some other async means, call resolve, passing in
            // the following args, plus a jQuery collection object
            // containing the DOM element for the page.
            data.deferred.resolve(url, data.options, $page);

            // update page url
            $.mobile.navigate(url, {});
        });
@dswitzer
dswitzer commented May 1, 2014

I tweaked the above code for my purposes:

$(document).on("pagecontainerloadfailed", function(event, data) {
    // Let the framework know we're going to handle things.
    event.preventDefault();

    // adjust the url so the back button works
    var url = data.absUrl.replace(/#.*?$/, '') + "#error";

    // Prepare your page structure
    var pagecontainer = new $.mobile.pagecontainer();
    var $page = pagecontainer._parse(data.xhr.responseText);

    // Append the new page into pageContainer
    $page.appendTo($.mobile.pageContainer);

    // ... attempt to load some other page ...
    // at some point, either in this callback, or through
    // some other async means, call resolve, passing in
    // the following args, plus a jQuery collection object
    // containing the DOM element for the page.
    data.deferred.resolve(url, data.options, $page);

    // if we had no content, we have an invalid jQuery Mobile result, so just update the entire page    
    if( $.trim($page.html()).length == 0 ){
        $("html").html("<body></body>").find("body").html(data.xhr.responseText);
    }

    // update page url
    $.mobile.navigate(url, {});
});

In our situation, when in development we spit out a big large document that isn't formatted for jQuery. The use of the pagecontainer_parse() uses the native JQM to format the content, but if it doesn't find the JQM markup, it'll return an empty DIV. So, we just clear the page so we can see the full error.

Since the page history is changed, once we resolve the error we can reload the page and the world is fine.

@thenewguy

I ended up refining this after I posted to use a popup dialog with an iframe and made use of html5 iframe srcdoc. There is a html5 shim for srcdoc as well which made this practical. This worked well for me. And then the error page styling isn't conflicting with jquery mobile.

@dswitzer
dswitzer commented May 1, 2014

After playing around with things, I came up with something much simpler that doesn't have any quirks that the previous script did:

// if an error occurs loading the page, the server will make sure we have a properly formatted document
$(document).on("pagecontainerloadfailed", function(event, data) {
    // let the framework know we're going to handle things.
    event.preventDefault();

    // get the page container
    var pagecontainer = $.mobile.pageContainer.data("mobilePagecontainer");

    // load the results as if they had succeeded
    pagecontainer._loadSuccess(data.absUrl, event, data.options, data.deferred)(data.xhr.responseText, "success", data.xhr);
});
@arschmitz
Member

@dswitzer this is something we are planning on implementing and this is essentially how it will work when we do so i would say this is the best workaround for now.

@thenewguy

If the error pages are formatted for jqm, this looks like a good way to handle it

@dswitzer
dswitzer commented May 1, 2014

Yeah, in our case the errors are in the expect jQM format. Our server-side framework double checks that.

Of course you could do a step further and have the server generate a specific header and only do the logic in the above block if that header is present. That would guarantee that you got back what you expected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment