A reader asked me to write a more complex jQuery Mobile authorization example. This one should prevent a user from going back to the “login” page if authorization was successful. It should also prevent us from using hash navigation and/or browser back/forward button. One last thing, this example will use standard jQuery Mobile Ajax page handling so we won’t reload pages at any point.
 
My original article was a simple one, showing only how to handle jQuery Mobile forms. I have intended for this to be a more complex one.
 
 

Note: If this tutorial was helpful, need further clarification, something is not working or do you have a request for another Ionic post? Furthermore, if you don't like something about this blog, if something is bugging you, don't like how I'm doing stuff here, again leave me a comment below. I'm here to help you, I expect the same from you. Feel free to comment below, subscribe to my blog, mail me to dragan.gaic@gmail.com, or follow and mention me on twitter (@gajotres). Thanks and have a nice day!

PS. If you want my help, if possible (even if it takes you some time to do that), create a working example I can play with. Use Plunker for AngularJS based questions or jsFiddle for jQuery/jQuery Mobile based questions.


 

Code

 
This example uses jQuery Mobile 1.4.5 and some functionalities are exclusive only to version 1.4 or above (once they become available).
 

HTML – index.php

 
<!DOCTYPE html>
<html>
<head>
    <title>jQM Complex Demo</title>
    <meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0"/>
    <link rel="stylesheet" href="http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.css" />
    <script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
    <script>
        $(document).on("mobileinit", function () {
          $.mobile.hashListeningEnabled = false;
          $.mobile.pushStateEnabled = false;
          $.mobile.changePage.defaults.changeHash = false;
        });
    </script>	
    <script src="http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.js"></script>
    <script src="js/index.js"></script>
</head>
<body>
    <div data-role="page" id="login" data-theme="b">
        <div data-role="header" data-theme="a">		
            <h3>Login Page</h3>
        </div>
 
        <div data-role="content">
            <form id="check-user" class="ui-body ui-body-a ui-corner-all" data-ajax="false">
                <fieldset>
                    <div data-role="fieldcontain">
                        <label for="username">Enter your username:</label>
                        <input type="text" value="" name="username" id="username"/>
                    </div>                                 
                    <div data-role="fieldcontain">                                     
                        <label for="password">Enter your password:</label>
                        <input type="password" value="" name="password" id="password"/>
                    </div>
                    <input type="button" data-theme="b" name="submit" id="submit" value="Submit">
                </fieldset>
            </form>                             
        </div>
 
        <div data-theme="a" data-role="footer" data-position="fixed">
 
        </div>
    </div>
    <div data-role="page" id="second">
        <div data-theme="a" data-role="header">
			<a href="#login" class="ui-btn-left ui-btn ui-btn-inline ui-mini ui-corner-all ui-btn-icon-left ui-icon-delete" id="back-btn">Back</a>		
            <h3>Welcome Page</h3>
        </div>
 
        <div data-role="content">
            
        </div>
 
        <div data-theme="a" data-role="footer" data-position="fixed">
            <h3>Page footer</h3>
        </div>
    </div>
</body>
</html>
 

PHP – auth.php

 
<?php
function authorize()
{
  //normally this info would be pulled from a database.
  //build JSON array
  $status = array("status" => "success"); 

  return $status;
}

$possible_params = array("authorization", "test");

$value = "An error has occurred";

if (isset($_POST["action"]) && in_array($_POST["action"], $possible_params))
{
  switch ($_POST["action"])
    {
      case "authorization":
        $value = authorize();
        break;
    }
}

//return JSON array
exit(json_encode($value));
?>
 

JavaScript – index.js

 
var userHandler = {
	username : '',
	status : ''
}

$(document).on('pagecontainershow', function (e, ui) {
    var activePage = $(':mobile-pagecontainer').pagecontainer('getActivePage');
    if(activePage.attr('id') === 'login') {
		$(document).on('click', '#submit', function() { // catch the form's submit event
			if($('#username').val().length > 0 && $('#password').val().length > 0){
			
				userHandler.username = $('#username').val();
			
				// Send data to server through the Ajax call
				// action is functionality we want to call and outputJSON is our data
				$.ajax({url: 'auth.php',
					data: {action : 'authorization', formData : $('#check-user').serialize()},
					type: 'post',                  
					async: 'true',
					dataType: 'json',
					beforeSend: function() {
						// This callback function will trigger before data is sent
						$.mobile.loading('show'); // This will show Ajax spinner
					},
					complete: function() {
						// This callback function will trigger on data sent/received complete	
						$.mobile.loading('hide'); // This will hide Ajax spinner
					},
					success: function (result) {
						// Check if authorization process was successful
						if(result.status == 'success') {
							userHandler.status = result.status;
							$.mobile.changePage("#second");                        
						} else {
							alert('Logon unsuccessful!');
						}
					},
					error: function (request,error) {
						// This callback function will trigger on unsuccessful action               
						alert('Network error has occurred please try again!');
					}
				});                  
			} else {
				alert('Please fill all necessary fields');
			}          
			return false; // cancel original event to prevent form submitting
		});  
    } else if(activePage.attr('id') === 'second') {
		activePage.find('.ui-content').text('Wellcome ' + userHandler.username);
	}
});

$(document).on('pagecontainerbeforechange', function (e, ui) {
    var activePage = $(':mobile-pagecontainer').pagecontainer('getActivePage');
    if(activePage.attr('id') === 'second') {
		var to = ui.toPage;
		
		if (typeof to  === 'string') {
			var u = $.mobile.path.parseUrl(to);
			to = u.hash || '#' + u.pathname.substring(1);
			 
			if (to === '#login' && userHandler.status === 'success') {
				alert('You cant open a login page while youre still logged on!');
				e.preventDefault();
				e.stopPropagation();
				 
				// remove active status on a button if a transition was triggered with a button
				$('#back-btn').removeClass('ui-btn-active ui-shadow').css({'box-shadow':'0 0 0 #3388CC'});
			} 
		}
	}
});
 

Walkthrough

 
First thing you need to understand is that jQuery Mobile uses a custom Ajax handling, we need to turn this off using this attribute: data-ajax=”false”, this way we have a full control over our authorization form.
 
<form id="check-user" class="ui-body ui-body-a ui-corner-all" data-ajax="false">
 
Because we are not going to reload pages (refresh) we will post our form data using classic Ajax call. To do this, we won’t use classic submit button, instead we will bind a click event to form button. When button is pressed it will initiate Ajax call.
 
<input type="button" data-theme="b" name="submit" id="submit" value="Submit">
 
$(document).on('click', '#submit', function() { // catch the form's submit event
 
Username and authorization status will be stored in an object, this way we can access them anytime we need.
 
var userHandler = {
	username : '',
	status : ''
}
 
Ajax call will use POST method and JSON as a data type. In case you are working on separate servers you will need to use GET method and JSONP as a data type (to prevent cross domain error). Async communication is used by default.
 
type: 'post',                  
async: 'true',
dataType: 'json',
 
Ajax loader animation will start before we send an Ajax call and will end when call ends (successfully or with an error).
 
beforeSend: function() {
    // This callback function will trigger before data is sent
    $.mobile.loading('show'); // This will show Ajax spinner
},
complete: function() {
    // This callback function will trigger on data sent/received complete	
    $.mobile.loading('hide'); // This will hide Ajax spinner
},
 
I will not create a full working PHP backend, each authorization call we end up as a successful authorization. If you need more than this you should code it yourself. My advice, use some kind of PHP/JAVA micro RESTFull framework. If you are using PHP you should read this article if you want to find a suitable RESTFull framework. If you are using Java I would recommend a Play Framework.
 
function authorize()
{
  //normally this info would be pulled from a database.
  //build JSON array
  $status = array("status" => "success"); 

  return $status;
}
 
If an authorization was successful javascript will store authorization state and allow a transition to the page #second.
 
if(result.status == 'success') {
    userHandler.status = result.status;
    $.mobile.changePage("#second");                        
} else {
 
To show you how data transfer works between pages we will display a welcome message for our authorized user. Username is retieved from our global javascript object.
 
} else if(activePage.attr('id') === 'second') {
    activePage.find('.ui-content').text('Wellcome ' + userHandler.username);
}
 
If at this point you try to move back (via application/browser back button) you will receive an alert: “Log off before you can move to the login page”. This is possible because we are evaluating destination/end point page plus authorization status (stored in global object).
 
if(activePage.attr('id') === 'second') {
    var to = ui.toPage;
		
    if (typeof to  === 'string') {
	var u = $.mobile.path.parseUrl(to);
	to = u.hash || '#' + u.pathname.substring(1);
		 
	    if (to === '#login' && userHandler.status === 'success') {
 
Browser back button is handled in mobileinit event. If you already don’t know mobileinit event must execute after jQuery is initialized but before jQuery Mobile initializes. We will configure jQuery Mobile not to use # URL navigation. You don’t need this code snippet if you are working on a mobile hybrid application. Take a look at this article if you want to learn how this functionality works.
 
<script>
$(document).on("mobileinit", function () {
    $.mobile.hashListeningEnabled = false;
    $.mobile.pushStateEnabled = false;
    $.mobile.changePage.defaults.changeHash = false;
});
</script>
 
These two lines will prevent page change:
e.preventDefault();
e.stopPropagation();
 
While this beautiful line will prevent button discoloration when we prevent page transition:

Who Am I?

Between working as a senior Java developer in one of the largest insurance companies in the world and traveling, in my free time, I work as a professional mobile development adviser. I'm also a major jQuery Mobile supporter back at StackOverflow and a forum moderator at the official Ionic Framework forum.

Blogs worth reading

If you're here looking for information related to the Ionic Framework, you will also like these blogs:






$('#back-btn').removeClass('ui-btn-active ui-shadow').css({'box-shadow':'0 0 0 #3388CC'});
 
  • John Lee

    Outstanding article! Worked wonderfully. I am new to mobile programming and this was exactly what I needed to get started. Thanks for your time and sharing.

  • Jerry

    Hey,
    I need you help. After login I would like to redirect the user to an index page that isn’t in the same document. I tried doing this
    $( “:mobile-pagecontainer” ).pagecontainer( “change”, “index.html”);
    But the redirection does not happen and I see the cross domain error in the browser. Please help I am stuck

    Error :
    XMLHttpRequest cannot load file:///C:/Users/nirav/Desktop/mobile/hiring/www/pages/question-list.html. Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https, chrome-extension-resource.

  • Alexander

    Hello Dragan,

    it is a good idea… but i have some Problems with the Response from the webservice
    in my envioment is a MS sql2008 Server an i give Login_name and Password as post
    as Response i have any variable for the next steps
    The webserver is xampp 3.21 with pdo

    When i startet, the Client give me a Network error back, see the

    index.js
    error: function (request,status,errorThrown) {
    // This callback function will trigger on unsuccessful action
    alert('Netzwerkfehler, bitte wiederholen!');
    alert(status);
    alert(errorThrown);

    Can you help me ??

    tanks Alexander

    see Webservice:
    <?php
    header('Content-Type: application/json');
    include 'config.php';

    error_reporting(0);

    $sql = "select a.form_of_adress as form_of_adress, e.firstname as firstname, e.lastname as lastname, e.employee_ID as employee_ID, e.client_ID as client_ID, e.secure_access as secure_access " .
    "from fewo_employees e, fewo_form_of_adress a " .
    "where e.login_name=:login_name and e.password=:password and e.form_of_adress_id = a.form_of_adress_id ";

    try {

    $dbh = new PDO("sqlsrv:Server=$dbhost;Database=$dbname", $dbuser, $dbpass);
    $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $stmt = $dbh->prepare($sql);

    // We don't need action for this tutorial, but in a complex code you need a way to determine Ajax action nature
    $action = $_POST['action'];
    // Decode JSON object into readable PHP object
    $formData = json_decode($_POST['formData']);

    // Get username
    $username = $formData->{'username'};
    // Get password
    $password = $formData->{'password'};

    //Mit Post scheint es nicht zu funktionieren
    $stmt->bindParam("login_name", $login_name);
    $stmt->bindParam("password", $password);

    $stmt->execute();
    $employeedetails = $stmt->fetchObject();
    $dbh = null;

    // Vorbelegen
    $output = array('status' => false, 'form_of_adress' => '', 'firstname' => '', 'lastname' => '', 'employee_ID' => '0', 'client_ID' => '0', 'secure_access' => '0');

    if (false===$employeedetails) {
    $output = array('status' => false, 'form_of_adress' => '', 'firstname' => '', 'lastname' => '', 'employee_ID' => '0', 'client_ID' => '0', 'secure_access' => '0');

    } else {
    $output = array('status' => true, 'form_of_adress' => $employeedetails->{'form_of_adress'}, 'firstname' => $employeedetails->{'firstname'}, 'lastname' => $employeedetails->{'lastname'}, 'employee_ID' => $employeedetails->{'employee_ID'},'client_ID' => $employeedetails->{'client_ID'}, 'secure_access' => $employeedetails->{'secure_access'});
    }
    echo json_encode($output);

    } catch(PDOException $e) {
    echo '{"error":{"text":'. $e->getMessage() .'}}';
    }
    ?>

    • Network error can mean anything.

      1. Have you received a server response?
      2. If you can see a server response can you tell me what does it say? Is it an error from your code or some PHP error?
      3. Have you tried to use Chrome Logger? This way you can debug PHP in your browser console.

  • dirtyrobinson

    This is the first example I've followed that's worked with page containers and I really like how you've explained a lot about Jquery Mobile in many other articles. Anyways, after playing around with this for a little bit, I started to see how this type of layout would feel with menus. It was adding page changes that started a problem. From a menu page, if you go to page 1, quickly go back to the menu, then back to page 1, then back to the menu, the page flashes the menu page for half a second, goes back to page 1 for another half a second before finally loading the menu. This seems to cause the rest of the page changes to seem buggy after as well.

    I'm not entirely sure what is causing it and how I could fix it but I'm hoping someone can help explain the issue to me. I posted a question on stackoverflow about this issue.
    http://stackoverflow.com/questions/28934411/jquery-mobile-document-onpagecontainershow-mobile-changepage

    I also provided an example, the example has page 1 and page 2 in separate HTML files but the issue is the same even if all 3 pages are in the same HTML file.
    https://www.mediafire.com/?v8tbifsix6fddxa

    Thanks

    • I have a working solution for your problem but this is not a right place to discuss it. Please create a new topic at my forum: http://www.gajotres.net/board/index/forum/ and I will write you everything you need to know. Plus give you a working example, or I can mail it back to you.

      • Jeff Barclay

        Your board link is dead 404, can you provide your solution here please, I know I’m a year late to the party, but I’m still looking for similar solution.

    • Jeff Barclay

      Both links are no longer helpful, please post fix here if available, I’m trying same code.

      • Jeff Barclay

        can anyone explain the “test” part of this? $possible_params = array(“authorization”, “test”);

        if I add case: test – nothing gets called?

  • Alexander

    Hello Dragan,

    I want to make a new auth.php with your example of auth…

    when I read the $_POST variable Login_name or Password, I get every time aNetwork error…
    see:
    <?php
    function authorize()
    {
    //normally this info would be pulled from a database.
    //build JSON array
    //$status = array("status" => "success","firstname" => "Alexander", "lastname" => "Test");

    $my_login_name = $_POST['login_name'];
    $my_password = $_POST['password'];

    $status = array("status" => "success","login_name" => $my_login_name, "password" => $my_password);

    return $status;
    }

    $possible_params = array("authorization", "login_name", "password");

    $value = "An error has occurred";

    if (isset($_POST["action"]) && in_array($_POST["action"], $possible_params))
    {
    switch ($_POST["action"])
    {
    case "authorization":
    $value = authorize();
    break;

    }
    }

    //return JSON array
    exit(json_encode($value));
    ?>

    have you any samples for validate the Login_name with a database and give other Information back to the form???
    thanks
    Alex

    • Hi Alexander,

      You didn't answer my questions to your previous question. I can't give you an answer without those additional information.

      1. Have you received a server response?
      2. If you can see a server response can you tell me what does it say? Is it an error from your code or some PHP error?
      3. Have you tried to use Chrome Logger? This way you can debug PHP in your browser console.
      4. Are you working in the same domain? (is your client side code in the same domain as a server side code or are you working on a hybrid mobile application and you're trying to connect to some server side code)

  • Vanessa Chad

    Thank you! Thank you! Thank you!