jQuery移动多页面等待ajax返回数据后才切换页面

时间:2022-08-23 17:51:40

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.

我正在以多页的形式使用jQuery mobile。当用户单击标有下一页的按钮时,我想运行一个AJAX请求。根据AJAX请求的结果,我希望阻止用户访问下一页。

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.

我认为我遇到的问题是,我的AJAX请求比下一个页面事件需要更长的时间来回复。因此,它允许用户进入下一页而不让AJAX请求完成。

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" .

在上面的代码示例中,当我单击Next Page按钮(即#btnPage2)时,它允许我访问第2页,尽管当我检查控制台日志时,我看到“第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

我试着把代码调整到下面。它可以工作,但是只有当用户不允许访问page2时。e。preventDefault就是让ajax完成,但我想不出一种方法来强制将页面改成page2。如果允许用户访问page2行

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

$(":mobile-pagecontainer”)。所以page2 pagecontainer(“改变”,“#”);

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

似乎是造成问题的原因……它只是创建一个调用pageChange事件的循环。我认为这是迫使页面更改为page2的一种方式,但我认为我错了,我不知道如何迫使它更改为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.

我尝试了实现@deblocker fix,但我还是遇到了同样的问题。当我在ajax设置不能传递到true的情况下运行以下代码时,代码似乎永远不会到达测试canNotPass值的点。因此,它永远不会设置e。preventDefault和用户可以访问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.

我认为这个解决方案与设置一个延迟对象有关,延迟对象允许ajax在页面更改发生之前完成。唯一的问题是我知道如何使用递延对象。

JSFiddle

JSFiddle

2 个解决方案

#1


2  

Use a button instead of an anchor:

使用按钮而不是锚:

<button id="btnPage2" class="ui-btn-right ui-icon-arrow-r">Next Page</a>

...and navigate by code inside the success handler:

…并通过代码在成功处理程序中导航:

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

$(":mobile-pagecontainer”)。所以page2 pagecontainer(“改变”,“#”);

BTW, you could also use some other handlers from ajax:

顺便说一句,您还可以使用ajax的其他处理程序:

$.ajax({
  type:...
  url:...
  data:...
  success: ...
  beforeSend: function() {
    $.mobile.loading("show");
  },
  complete: function() {
    $.mobile.loading("hide");
  },
  error: function (request,error) {
    alert('sorry you can not enter page 2');
});

UPDATE:

更新:

Following Omar's suggestion, inside the first part of the pagecontainerbeforechange handler you should break the navigation, as you are already on the half way to page2. So, you don't need anymore to tell to pagecontainer to switch to page2 inside the pagecontainerbeforechange event here. You should simply keep your ajax request and your canNotPass flag inside $('#btnPage2').click().

按照Omar的建议,在pagecontainerbeforechange处理程序的第一部分中,您应该中断导航,因为您已经在page2的半路上了。因此,您不再需要告诉pagecontainer在这里切换到pagecontainerbeforechange事件中的page2。您应该将ajax请求和不能传递标志保存在$('#btnPage2')内。

DEMO:

演示:

$(document).on("pagecontainerbeforechange", function(e, ui) {
  var from = "#" + $(":mobile-pagecontainer").pagecontainer("getActivePage").prop("id");
  var to = ui.toPage;	
  if (typeof ui.toPage == "string") {
    var u = $.mobile.path.parseUrl(to);
    to = u.hash || "#" + u.pathname.substring(1);
    if (from === "#page-one" && to === "#page-two") {
      var canNotPass = !$("#canPass").prop("checked");
      if(canNotPass) {
        e.preventDefault();
        $.mobile.activePage.find('.ui-btn-active').removeClass('ui-btn-active').blur();
      }
    }
  }
});
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
  <link rel="stylesheet" href="https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.css">
  <script src="https://code.jquery.com/jquery-1.11.2.min.js"></script>
  <script src="https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.js"></script>
</head>
<body>
  <div data-role="page" id="page-one">
    <div data-theme="a" data-role="header" data-position="fixed">
      <h1>First Page</h1>
      <a href="#page-two" class="ui-btn-left">Next</a>
    </div>
    <div data-role="content">
      <label for="canPass">Can Navigate to Page 2 ?</label>
      <input data-role="flipswitch" name="canPass" id="canPass" data-on-text="Yes" data-off-text="No" type="checkbox">
    </div>
    <div data-theme="a" data-role="footer" data-position="fixed">
      <h1>Footer</h1>
    </div>
  </div>
  <div data-role="page" id="page-two">
    <div data-theme="a" data-role="header" data-position="fixed">
      <h1>Second Page</h1>
      <a href="#page-one" class="ui-btn-left">Back</a>
    </div>
    <div data-role="content">
    </div>
    <div data-theme="a" data-role="footer" data-position="fixed">
      <h1>Footer</h1>
    </div>
  </div>
</body>
</html>

EDIT2: (Credits: Omar) - Here is how to trap the direct navigation to that "protected" page

(字幕:奥马尔)这里是如何捕获到“受保护”页面的直接导航

$(document).on("pagecontainerbeforechange", function(e, ui) {
  /* in case user enter foo.com/#page2 directly */
  if (typeof ui.toPage === "object" && ui.absUrl === undefined && ui.toPage[0].id == "page2") {
    /* make ajax call */
    var ajaxCall = true;
    if (ajaxCall) {
      $.noop
    } else {
      ui.toPage = "#noAccessPage"
    }
  }

  /* internal navigation from page1 to page2 */
  if (typeof ui.toPage === "string" && ui.absUrl !== undefined && $.mobile.path.parseUrl(ui.absUrl).hash == "#page2") {
    /* make ajax call */
    var ajaxCall = true;
    if (ajaxCall) {
      $.noop
    } else {
      ui.toPage = "#noAccessPage"
    }
  }
});

#2


0  

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>

<按钮id="btnnewpage"> 到第2页

$(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
            });
}

#1


2  

Use a button instead of an anchor:

使用按钮而不是锚:

<button id="btnPage2" class="ui-btn-right ui-icon-arrow-r">Next Page</a>

...and navigate by code inside the success handler:

…并通过代码在成功处理程序中导航:

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

$(":mobile-pagecontainer”)。所以page2 pagecontainer(“改变”,“#”);

BTW, you could also use some other handlers from ajax:

顺便说一句,您还可以使用ajax的其他处理程序:

$.ajax({
  type:...
  url:...
  data:...
  success: ...
  beforeSend: function() {
    $.mobile.loading("show");
  },
  complete: function() {
    $.mobile.loading("hide");
  },
  error: function (request,error) {
    alert('sorry you can not enter page 2');
});

UPDATE:

更新:

Following Omar's suggestion, inside the first part of the pagecontainerbeforechange handler you should break the navigation, as you are already on the half way to page2. So, you don't need anymore to tell to pagecontainer to switch to page2 inside the pagecontainerbeforechange event here. You should simply keep your ajax request and your canNotPass flag inside $('#btnPage2').click().

按照Omar的建议,在pagecontainerbeforechange处理程序的第一部分中,您应该中断导航,因为您已经在page2的半路上了。因此,您不再需要告诉pagecontainer在这里切换到pagecontainerbeforechange事件中的page2。您应该将ajax请求和不能传递标志保存在$('#btnPage2')内。

DEMO:

演示:

$(document).on("pagecontainerbeforechange", function(e, ui) {
  var from = "#" + $(":mobile-pagecontainer").pagecontainer("getActivePage").prop("id");
  var to = ui.toPage;	
  if (typeof ui.toPage == "string") {
    var u = $.mobile.path.parseUrl(to);
    to = u.hash || "#" + u.pathname.substring(1);
    if (from === "#page-one" && to === "#page-two") {
      var canNotPass = !$("#canPass").prop("checked");
      if(canNotPass) {
        e.preventDefault();
        $.mobile.activePage.find('.ui-btn-active').removeClass('ui-btn-active').blur();
      }
    }
  }
});
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
  <link rel="stylesheet" href="https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.css">
  <script src="https://code.jquery.com/jquery-1.11.2.min.js"></script>
  <script src="https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.js"></script>
</head>
<body>
  <div data-role="page" id="page-one">
    <div data-theme="a" data-role="header" data-position="fixed">
      <h1>First Page</h1>
      <a href="#page-two" class="ui-btn-left">Next</a>
    </div>
    <div data-role="content">
      <label for="canPass">Can Navigate to Page 2 ?</label>
      <input data-role="flipswitch" name="canPass" id="canPass" data-on-text="Yes" data-off-text="No" type="checkbox">
    </div>
    <div data-theme="a" data-role="footer" data-position="fixed">
      <h1>Footer</h1>
    </div>
  </div>
  <div data-role="page" id="page-two">
    <div data-theme="a" data-role="header" data-position="fixed">
      <h1>Second Page</h1>
      <a href="#page-one" class="ui-btn-left">Back</a>
    </div>
    <div data-role="content">
    </div>
    <div data-theme="a" data-role="footer" data-position="fixed">
      <h1>Footer</h1>
    </div>
  </div>
</body>
</html>

EDIT2: (Credits: Omar) - Here is how to trap the direct navigation to that "protected" page

(字幕:奥马尔)这里是如何捕获到“受保护”页面的直接导航

$(document).on("pagecontainerbeforechange", function(e, ui) {
  /* in case user enter foo.com/#page2 directly */
  if (typeof ui.toPage === "object" && ui.absUrl === undefined && ui.toPage[0].id == "page2") {
    /* make ajax call */
    var ajaxCall = true;
    if (ajaxCall) {
      $.noop
    } else {
      ui.toPage = "#noAccessPage"
    }
  }

  /* internal navigation from page1 to page2 */
  if (typeof ui.toPage === "string" && ui.absUrl !== undefined && $.mobile.path.parseUrl(ui.absUrl).hash == "#page2") {
    /* make ajax call */
    var ajaxCall = true;
    if (ajaxCall) {
      $.noop
    } else {
      ui.toPage = "#noAccessPage"
    }
  }
});

#2


0  

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>

<按钮id="btnnewpage"> 到第2页

$(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
            });
}