Search code examples
jqueryajaxjquery-mobilejquery-mobile-ajax

jQuery mobile multipage wait for ajax to return data before switching pages


I'm using jQuery mobile in a multi page form. When the user clicks the button labeled Next Page I want to run an AJAX request. Depending on the result of the AJAX request, I would want to prevent the user from accessing the next page.

I believe the problem I'm running into is that my AJAX request takes longer to reply than the next page event. Therefore, it's letting the user enter the next page without letting the AJAX request finish.

At least I think that's what is happening. Has anyone run into this before or know of a solution to this problem?

HTML:

<div id="page1" data-role="page">
    <div data-role="header" data-position="fixed" data-theme="d">
        <a href="#page2" data-role="button" id="btnPage2" class="ui-btn-right" data-icon="arrow-r">Next Page</a>
    </div>
    <div role="main" class="ui-content">
        <label for="testVal">Test Val:</label>
        <input type="text" id="testVal" name="testVal"/>
    </div>
</div>
<div id="page2" data-role="page">
    <div role="main" class="ui-content">

    </div>
</div> 

jQuery:

$('#btnPage2').click(function(){
    var isValid = '';
    var aValue = $('#testVal').val();
    $.ajax({
        type: "POST",
        url: "php-file.php",
        data: {"something":aValue },
        success: function(data){
            var json = $.parseJSON(data);
            if(json.hasOwnProperty('error')){
                console.log("the user is not allowed on page 2");
                isValid = false;
            }else{
                isValid = true;
            }
        }
    });
    if(!isValid){
        alert('sorry you can not enter page 2');
        return false;
    }
});

In the code sample above when I click the Next Page button (i.e. #btnPage2) it allows me to access page 2 even though when I check the console log and I see "the user is not allowed on page 2" .

UPDATE:

I tried adjusting the code to the following. It kind of works but, only when the user is not allowed to access page2. e.preventDefault is letting ajax finish but, I can't figure out a way to force a change to page2. If the user is allowed access to page2 the line

$(":mobile-pagecontainer").pagecontainer("change", "#page2");

seems to be causing the problem...it just creates an endless loop of calling the pageChange event. I thought that is the way to force a page change to page2 but I think i'm wrong and I cannot figure out how to force it to change to page2

$(document).bind('pagebeforechange', function(e, data) {
    var to = data.toPage,
        from = data.options.fromPage;

    if (typeof to === 'string') {
        var u = $.mobile.path.parseUrl(to);
        to = u.hash || '#' + u.pathname.substring(1);
        if (from) from = '#' + from.attr('id');

        if (from === '#page1' && to === '#page2') {
        e.preventDefault();
        var aValue = $('#testVal').val();
            $.ajax({
                type: "POST",
                url: "php-file.php",
                data: {"something":aValue },
                cache: false,
                success: function(data){
                    var json = $.parseJSON(data);
                    if(json.hasOwnProperty('canNotPass')){
                        alert('Sorry you can not view page 2');
                    }else{
                        ///  if json does not contain canNotPass then continue to page2 
                        $(":mobile-pagecontainer").pagecontainer("change", "#page2");
                    }
                },
                beforeSend: function() {
                    $.mobile.loading("show");
                },
                complete: function() {
                    $.mobile.loading("hide");
                }
            });   
        }            
    }
});

UPDATE #2

I tried implementing @deblocker fix and I'm still coming up with the same problem. When I run the following code in a situation where ajax sets canNotPass to true the code never seems to get to the point where is tests the value of canNotPass. Therefore, it never gets to set e.preventDefault and the user is allowed access to page2.

I think the solution has something to do with setting up a deferred object which would allow time for the ajax to finish before the page change occurs. Only problem is I have know idea how to set up/work with deferred objects.

JSFiddle


Solution

  • Thanks Omar and deblocker for spending so much time on this issue. Unfortunately, I was unable to implement your suggestions without interfering with the rest of my page interactions. The only solution I came up with that works is listed below. Unfortunately, this solution does not use the built in hash functions that handle the page change event. I just use a normal button and assign click listener to it. A bit clunky but it seems to be the only way it can work in my situation.

    <button id="btnNewPage">Go To Page 2</button>

    $(document).ready(function(){
        $("#btnPageNew").click(function(){
            var testVal = $('#testVal').val();
            var canNotPass = promiseTest(testVal);
                canNotPass.done(function(data){
                    var json = $.parseJSON(data);
                        console.log(json);
                        if(json.hasOwnProperty('error')){
                            // user can not access the next page
                            console.log('can not pass');
                            $.mobile.activePage.find('.ui-btn-active').removeClass('ui-btn-active').blur();
                        }else{
                            // allow user to access the next page
                            $(":mobile-pagecontainer").pagecontainer("change", "#page2");
                        }
                });
    
    
        });
    });
    
    function promiseTest(aValue){
        return $.ajax({
                    type: "POST",
                    url: "php-file.php",
                    data: {"something":aValue  },
                    cache: false
                });
    }