Changing link destination with the pagebeforechange event and keeping it out of the history? - jquery-mobile

I am working on a PhoneGap application that uses jQuery Mobile (jQM). This application has areas that will require the user to be authenticated. So I'm using jQM's pagebeforechange to determine if the user needs to authenticate before viewing the page they have requested. If so, I send them to a login page.
I want to keep the login page out of jQM's history tracking. That is, if the user is presented with the login page, but decides to press "cancel," I want the application to go back to the previous page and not have a "next" page in the history; the "previous page" would be at the top of the history stack.
Here's how I am handling the login page redirection:
$(document).bind('pagebeforechange', function(e, data) {
if (typeof data.toPage !== 'string') {
return;
}
if (data.toPage.match(/someRestrictedPage/)) {
data.options.transition = "pop";
data.options.changeHash = false;
data.toPage = "myLogin.html";
}
});
For the cancel button of my login page I am doing:
$loginCancelButton.bind('click', function() {
var prevPage = $.mobile.urlHistory.getPrev();
if (typeof prevPage !== 'undefined') {
$.mobile.changePage(prevPage.url, {
changeHash: false,
reverse: true,
transition: "pop"
});
}
});
However, when I do this, I end up with a $.mobile.urlHistory.stack with three elements:
[ {"index"}, {"login"}, {"index"} ]
How do I manage intercepting page changes to redirect to a login form when necessary, but not create an "invalid" navigation history?

looking at the jquery docs it mentions that pagebeforeload event needs to be stopped. and then call the data.deferred (resolve or reject).
try changing it to:
$(document).bind('pagebeforechange', function(e, data) {
if (typeof data.toPage !== 'string') {
return;
}
if (data.toPage.match(/someRestrictedPage/)) {
e.preventDefault()
data.options.transition = "pop";
data.options.changeHash = false;
data.toPage = "myLogin.html";
}
data.deferred.resolve(/* url */, data.options)
});

A solution for the initial problem could be something like:
$(document).bind('pagebeforechange', function(e, data) {
if (typeof data.toPage !== 'string') {
return;
}
if (data.toPage.match(/ your regex /gi))
{
if (!check_login())
{
e.preventDefault();
data.options.transition = "pop";
data.options.changeHash = false;
data.toPage = "#SignIn";
$.mobile.changePage("#SignIn");
}
//data.deferred.resolve('#SignIn', data.options);
}
});
That worked for me just fine.

VeXii's solution seemed to work for me. By simply removing
data.deferred.resolve('#SignIn', data.options);
and
e.preventDefault();
On jquery mobile 1.3...
$(document).bind('pagebeforechange', function(e, data) {
if (typeof data.toPage !== 'string') {
return;
}
if (data.toPage.match(/index/)) {
data.options.transition = "pop";
data.options.changeHash = false;
data.toPage = "#login";
}
});

Related

JQuery Mobile 1.4.2 - Showing Popup on Page Load

I am trying to show a popup when a page loads. I have a generic popup embedded in each page that should be shown if there are data in the popup itself. Here is the code I'm trying to use:
$(function() { // initial page load
$(document).on("pagechange",
function(event) {
var pageId = $(document).pagecontainer( "getActivePage" )[0].id;
displayMessages(pageId);
});
});
}
I've looked at every other sample I've seen on StackOverflow, but none of them seem to work. The error I'm getting is:
Error: cannot call methods on popup prior to initialization;
attempted to call method "open".
So, when can I call popup("open") on a popup?
EDIT TO INCLUDE displayMessage FUNCTION
function displayMessages(pageId) {
pageId = pageId || $("body").pagecontainer( "getActivePage" )[0].id;
try {
var errCount = parseInt( $(jq(pageId + ".errorCount")).val() );
if ( !isNaN(errCount) && errCount )
{
$( jq(pageId + ".errors") ).popup( "open" );
}
else if ( $(jq(pageId + ".message")).text() != "" )
{
$( jq(pageId + ".message") ).popup( "open" );
}
} catch (e) {
alert(e);
}
}

jQuery-Mobile: Page does not load completely when swiped to

Today I prepared some PHP pages with jQuery-Mobile. It should enable for swiping from one page to another.
In general the swiping works but there is one problem: When I've swiped to a new page swiping doesn't work on that page first. Only when I reload the page it works again. The page source before reloading is OK.
It seems to me that not all inclusions are executed when I have swiped to a new page. How can this be fixed? E.g.: Ref link
$(document).ready(function () {
var urlup, urlleft, urlright;
$('img').on('dragstart', function (event) {
event.preventDefault();
});
$('img').each(function (i) {
if (this.src.indexOf("buttonup.png") >= 0) {
urlup = this.parentNode.href;
this.id = "buttonup";
} else if (this.src.indexOf("buttonleft.png") >= 0) {
urlleft = this.parentNode.href;
this.id = "buttonleft"
} else if (this.src.indexOf("buttonright.png") >= 0) {
urlright = this.parentNode.href;
this.id = "buttonright";
} else {};
});
//$.mobile.loadPage(urlup);
//$.mobile.loadPage(urlleft);
//$.mobile.loadPage(urlright);
$(":mobile-pagecontainer").pagecontainer("load", urlup);
$(":mobile-pagecontainer").pagecontainer("load", urlleft);
$(":mobile-pagecontainer").pagecontainer("load", urlright);
$(document).on("swipeup", function () {
$.mobile.changePage(urlup);
});
$(document).on("swipeleft", function () {
$.mobile.changePage(urlright);
});
$(document).on("swiperight", function () {
$.mobile.changePage(urlleft, {
reverse: true
});
});
$("#buttonup").click(function () {
$.mobile.changePage(urlup, {
transition: "slideup"
});
});
$("#buttonleft").click(function (event) {
event.stopPropagation();
});
$("#buttonleft").click(function () {
$.mobile.changePage(urlleft, {
reverse: true
});
});
$("#buttonright").click(function () {
$.mobile.changePage(urlright);
});
});
In the meantime I was able to fix this problem: I used the document-ready-event and this one is not fired when jQuery Mobile loads a new page. Thus the javascript code that binds the swiping events was not executed. I had to use JMs pageinit event instead. After fixing some other problems swiping works fine on my pages now:
http://www.ulrichbangert.de/orchid/odm_rawdonjester.php
Best regards - Ulrich

JQueryMobile: pagecontainershow on a particular page not working

JQueryMobile 1.4 has deprecated the pageshow event and instead recommends using pagecontainershow; however, while I'm able to get the pagecontainershow event at a document level, I can't bind a function to a particular page.
<div id="page1" data-role="page">
...
<script>
$( "#page1" ).on( "pagecontainershow", function( event, ui ) {
console.log("page1 pagecontainershow");
} );
</script>
</div>
Demonstration: http://jsbin.com/IFolanOW/22/edit?html,console,output
I also considered using the alternative form of the jQuery "on" function where we use a selector, but that would need to be a parent of the page div, and that might include other pages, so that doesn't work.
As a workaround, I've done this, but it is very inefficient:
function registerOnPageShow(pageId, func) {
var strippedPageId = pageId.replace("#", "");
var e = "pagecontainershow." + strippedPageId;
// TODO why isn't it working to use $(pageId) instead of $(document)?
$( document ).off(e).on(e, null, {page: strippedPageId, f: func}, function(e, ui) {
if ($(":mobile-pagecontainer").pagecontainer("getActivePage")[0].id == e.data.page) {
e.data.f(e, ui);
}
});
}
You can get the page ID like this.
$(document).on('pagecontainershow', function(e, ui) {
var pageId = $('body').pagecontainer('getActivePage').prop('id');
});
There is currently no way to have a show/hide event on a specific page.
Here is what I'm using (jqmobile >1.4):
$(document).on("pagecontainershow", function () {
var activePage = $.mobile.pageContainer.pagecontainer("getActivePage");
var activePageId = activePage[0].id;
switch (activePageId) {
case 'loginPage':
...
break;
case 'homePage':
...
break;
case 'groupPage':
...
break;
default:
}
});
$(document).on("pagecontainershow", function(event, ui) {
var pageId = $('body').pagecontainer('getActivePage').prop('id'),
showFunc = pageId+'_show';
if (typeof MobileSite[showFunc] == 'function') {
MobileSite[showFunc]();
}
});
MobileSite is contained in an external .js file with all the show() functions.
$(document).on("pagecontainerbeforeshow", function (event, ui) {
if (typeof ui.toPage == "object") {
var crrentPage = ui.toPage.attr("id")
}
});
and you must use this code before calling Index.js !!

jQuery Mobile swipe navigation exception

I have a series of pages inside one document, I navigate from page to page making use of swipe in touch devices.
What I dont know how to do, is to stop the swipe event once I reach certain page id.
This is the code I am using form my navigation:
$('div.ui-page').live("swipeleft", function(){
var nextpage = $(this).next('div[data-role="page"]');
if (nextpage.length > 0) {
$.mobile.changePage(nextpage, "slide", false, true);
}
});
$('div.ui-page').live("swiperight", function(){
var prevpage = $(this).prev('div[data-role="page"]');
if (prevpage.length > 0) {
$.mobile.changePage(prevpage, {transition: "slide",
reverse: true}, true, true);
}
});
I am using JQM 1.3
Thank you for your help
Here's a working example: http://jsfiddle.net/Gajotres/GXex5/
$(document).off('swipeleft').on('swipeleft', '[data-role="page"]', function(event){
if($(this).attr('id') == 'article2') {
event.preventDefault();
return false;
}
var nextpage = $.mobile.activePage.next('[data-role="page"]');
// swipe using id of next page if exists
if (nextpage.length > 0) {
$.mobile.changePage(nextpage, {transition: "slide", reverse: false}, true, true);
}
event.handled = true;
});
$(document).off('swiperight').on('swiperight', '[data-role="page"]', function(event){
var prevpage = $(this).prev('[data-role="page"]');
if (prevpage.length > 0) {
$.mobile.changePage(prevpage, {transition: "slide", reverse: true}, true, true);
}
event.handled = true;
});
Basically all you need is this code:
if($(this).attr('id') == 'article2') {
event.preventDefault();
return false;
}
This code will check if some page has a certain name and if it is so it will prevent default action (event). Also dont forget to pass a event object in your code, so
change this:
$('div.ui-page').live("swiperight", function(){
to this:
$('div.ui-page').live("swiperight", function(event){
Use the below to define next and previous page ID, if it equals to the page you don't want to show, do nothing.
var DoNothing = 'DoNothing';
// fetch ID of next page in DOM
var nextpage = $.mobile.activePage.next('[data-role=page]')[0].id;
// fetch ID of previous page in DOM
var prevpage = $.mobile.activePage.prev('[data-role=page]')[0].id;
// logic
if(nextpage == DoNothing || prevpage == DoNothing) {
// Do nothing!
}

Post data to controller with JQuery via login screen

I have a section in my ASP.NET MVC3 website where a user can click a button to add an entry to their 'Saved Items' section in their account. This is done via a JQuery Ajax request, which works well if they're logged in. If they're not logged in, I'd like them to be redirected to a login page, and then automatically have the entry added to their Saved Items section.
I have all the parts working seperately - i.e. when the button is clicked, if not logged in, the login box displays. The login popup also works successfully. The problem is trying to seamlessly do all things at once. Here is the code I have so far:
Click event for Save button - checks to see if user logged in along the way:
var loggedIn = false;
$(document).ready(function () {
$('a#saveSearch').live('click', function (event) {
$.get('#Url.Action("IsLoggedIn", "Account", null)', function (response) {
if (response == "True")
loggedIn = true;
else
loggedIn = false;
});
if (loggedIn){
SaveSearch();
}
else{
$('#dialog').dialog('open');
SaveSearch(); //don't think this is correct because it hits this line before login is complete
}
});
Function to save to database:
function SaveSearch(){
var url = '#Url.Action("SaveSearch", "User")';
$.ajax({
url: url,
type: 'POST',
contentType: "application/json; charset=utf-8",
data: JSON.stringify({
json: "#Html.Raw(Session["MyFormString"].ToString())"
}),
success: function (data) {
$('a#saveSearch').attr('disabled', "disabled");
$('div#savedResponse').html('<p>Search saved to user account</p>');
},
error: function () {
}
});
}
});
JQuery UI dialog popup:
$(function () {
$('#dialog').dialog({
autoOpen: false,
width: 400,
resizable: false,
title: 'Login',
modal: true,
open: function(event, ui) {
$(this).load("#Url.Action("Logon", "Account", null)");
},
buttons: {
"Close": function () {
$(this).dialog("close");
}
}
});
I think there is something fundamental that is wrong with my code, because this way, the login popup appears for just a second and then disappears straight away. It looks like I need to get it to stop advancing through the code until the login has been completed.
Any advice or help to get this going would be appreciated.
I would imagine your issue might be related to:
$.get('#Url.Action("IsLoggedIn", "Account", null)', function (response) {
if (response == "True")
loggedIn = true;
else
loggedIn = false;
});
if (loggedIn){
SaveSearch();
}
else{
$('#dialog').dialog('open');
SaveSearch(); //don't think this is correct because it hits this line before login is complete
}
The $.get call is async, which means the latter code:
if (loggedIn){
Is being executed before the server has responded. You need to put that code within your response callback:
$.get('#Url.Action("IsLoggedIn", "Account", null)', function (response) {
if (response == "True")
loggedIn = true;
else
loggedIn = false;
if (loggedIn){
SaveSearch();
}
else{
$('#dialog').dialog('open');
SaveSearch(); //don't think this is correct because it hits this line before login is complete
}
});
Try and add a close callback function to your modal, then the code will only be done as soon as the modal is closed and all the login have been done sucessfully. See comments in your code
$(document).ready(function () {
$('a#saveSearch').live('click', function (event) {
$.get('#Url.Action("IsLoggedIn", "Account", null)', function (response) {
if (response == "True")
loggedIn = true;
else
loggedIn = false;
});
if (loggedIn){
SaveSearch();
}
else{
//in this dialog, add a close handler,then add the SaveSearch(); function in that handler
$('#dialog').dialog('open');
}
});

Resources