Showing posts with label ajax. Show all posts
Showing posts with label ajax. Show all posts

Simple AJAX with jQueryUI and PHP

This will be a short tutorial on how to incorporate AJAX interaction into a PHP site using jQuery and the jQueryUI framework.


Imagine we have a page that lets users manage a list of books that is stored in a database.  We want them to be able to easily edit the books via ajax without having to go to another page. Below is an example of what we want.



Here's the database table we'll use plus a few sample books.


CREATE TABLE `books` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(30) NOT NULL,
  `genre` enum('fantasy','mystery','nonfiction') NOT NULL,
  `description` text NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE = InnoDB;

INSERT INTO `book` (`id`, `title`, `genre`, `description`) VALUES
(1, 'The Lord of the Rings', 'fantasy', 'The Lord of the Rings is an epic fantasy novel written by philologist and University of Oxford professor J. R. R. Tolkien (from Wikipedia).'),
(2, 'The Maltese Falcon', 'mystery', 'The Maltese Falcon is a 1930 detective novel by Dashiell Hammett, originally serialized in the magazine Black Mask (from Wikipedia).'),
(3, 'Economics in One Lesson', 'nonfiction', 'Economics in One Lesson is an introduction to free market economics written by Henry Hazlitt and published in 1946, based on Frédéric Bastiat''s essay Ce qu''on voit et ce qu''on ne voit pas (English: "What is Seen and What is Not Seen") (from Wikipedia).');


First, let's create the PHP page that pulls these books from the database and displays them to the user. Later, we'll add javascript code to this page to make the edit link use AJAX to interact with the database.

//display.php
<div class='books'>
 <?php
 //connect to database
 mysql_connect('localhost', 'mysql_user', 'mysql_password');
 mysql_select_db('dbname');

 //get all books
 $query = "SELECT * FROM books";
 $result = mysql_query($query) or die("Error selecting books");

 //display books
 while($row = mysql_fetch_assoc($result)) {
 ?>
  <div class='book' id='book_<?php echo $row['id']; ?>'>
   <a class='edit' href='#'>edit</a>
   <h3 class='title'><?php echo $row['title']; ?></h3>
   <p><em class='genre'><?php echo $row['genre']; ?></em></p>
   <p class='description'><?php echo $row['description']; ?></p>
  </div>
 <?php
 }
 ?>
</div>

The next page to create is the edit.php page that the ajax link will call.


//edit.php
<?php
//connect to database
mysql_connect('localhost', 'mysql_user', 'mysql_password');
mysql_select_db('dbname');

//pull info from $_POST and sanitize it
$id = mysql_real_escape_string($_POST['id']);
$title = mysql_real_escape_string($_POST['title']);
$genre = mysql_real_escape_string($_POST['genre']);
$description = mysql_real_escape_string($_POST['description']);

//update in database
$query = 'Update books SET title="'.$title.'", genre="'.$genre.'", description="'.$description.'" WHERE id="'.$id.'"';
mysql_query($query);

//generate json code
echo json_encode(array(
 'id'=>$id,
 'title'=>$title,
 'genre'=>$genre,
 'description'=>$description
));
?>

When the user clicks the edit link for a book, we want a dialog box to pop up with a form that lets the user edit the data. We want the form to submit to the edit.php page via AJAX. Finally, we want the page to update to reflect the changes.


To do this, we first create the html for the dialog box. The submit button will be handled by jQuery, so we don't need to add it here. This goes at the bottom of the display.php page.


<div id='edit_dialog'>
 <form action='edit.php' method='post'>
  <input type='hidden' name='id' />

  Title: 
  <input type='text' name='title' /><br />
  
  Genre:
  <select name='genre'>
   <option value='fantasy'>Fantasy</option>
   <option value='mystery'>Mystery</option>
   <option value='nonfiction'>Nonfiction</option>
  </select><br />
  
  Description:
  <textarea name='description' cols='30' rows='3'></textarea>  
 </form>
</div>

Now we add the jQuery code to the display.php page to tie everything together. This requires jQuery, jQueryUI with the dialog widget, and a jQueryUI theme to be loaded. This goes somewhere on the display.php page.


$(document).ready(function() {
 //Create dialog
 $edit_dialog = $("#edit_dialog").dialog({
  autoOpen:false, 
  title:"Edit Book", 
  modal:true, 
  buttons:[
   {text: "Submit", click: function() { $('form',$(this)).submit(); }},
   {text: "Cancel", click: function() { $(this).dialog("close"); }},
  ]
 });
 
 //Submit action for dialog form
 $("#edit_dialog form").submit(function() {
  var form = $(this);
  //post form data to form's action attribute
  $.post($(this).attr('action'), $(this).serialize(),function(data) {   
   //get DOM element of updated book
   var book = $('#book_'+data.id);
  
   //update title
   $('.title',book).html(data.title);
   
   //update genre
   $('.genre',book).html(data.genre);
   
   //update description
   $('.description',book).html(data.description);
  
   //close the dialog
   $("#edit_dialog").dialog('close');
  },'json');
  
  //stop default form submit action
  return false;
 });

 //when the edit link is clicked
 function edit_link_action() {
  //get closest book div
  var book = $(this).closest('.book');
  
  //get id from div
  var id = book.attr('id').split('_');
  id = id[id.length-1];
  
  //set id in form
  $('#edit_dialog input[name="id"]').val(id);
  
  //set current title in form
  $('#edit_dialog input[name="title"]').val($('.title',book).html());
  
  //set current genre in form
  $('#edit_dialog select[name="genre"]').val($('.genre',book).html());
  
  //set current description in form
  $('#edit_dialog textarea[name="description"]').val($('.description',book).html());
  
  //open dialog
  $edit_dialog.dialog('open');
  
  //stop default link action
  return false;
 }
 
 //attach action to edit links
 $(".edit").click(edit_link_action);
});

Once all the parts are put together, you should have a fully functioning AJAX site. Below is the complete code for the display.php page.


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
 <script type='text/javascript' src='jquery-1.4.4.min.js'></script>
 <script type='text/javascript' src='jquery-ui-1.8.9.custom.min.js'></script>
 <link rel='stylesheet' href='jquery-ui-1.8.9.custom.css' />
 <script type='text/javascript'>
  $(document).ready(function() {
   //Create dialog
   $edit_dialog = $("#edit_dialog").dialog({
    autoOpen:false, 
    title:"Edit Book", 
    modal:true, 
    buttons:[
     {text: "Submit", click: function() { $('form',$(this)).submit(); }},
     {text: "Cancel", click: function() { $(this).dialog("close"); }},
    ]
   });
   
   //Submit action for dialog form
   $("#edit_dialog form").submit(function() {
    var form = $(this);
    //post form data to form's action attribute
    $.post($(this).attr('action'), $(this).serialize(),function(data) {   
     //get DOM element of updated book
     var book = $('#book_'+data.id);
    
     //update title
     $('.title',book).html(data.title);
     
     //update genre
     $('.genre',book).html(data.genre);
     
     //update description
     $('.description',book).html(data.description);
    
     //close the dialog
     $("#edit_dialog").dialog('close');
    },'json');
    
    //stop default form submit action
    return false;
   });

   //when the edit link is clicked
   function edit_link_action() {
    //get closest book div
    var book = $(this).closest('.book');
    
    //get id from div
    var id = book.attr('id').split('_');
    id = id[id.length-1];
    
    //set id in form
    $('#edit_dialog input[name="id"]').val(id);
    
    //set current title in form
    $('#edit_dialog input[name="title"]').val($('.title',book).html());
    
    //set current genre in form
    $('#edit_dialog select[name="genre"]').val($('.genre',book).html());
    
    //set current description in form
    $('#edit_dialog textarea[name="description"]').val($('.description',book).html());
    
    //open dialog
    $edit_dialog.dialog('open');
    
    //stop default link action
    return false;
   }
   
   //attach action to edit links
   $(".edit").click(edit_link_action);
  });
 </script>
</head>
<body>
 <div class='books'>
  <?php
  //connect to database
  mysql_connect('localhost', 'mysql_user', 'mysql_password');
  mysql_select_db('dbname');

  //get all books
  $query = "SELECT * FROM books";
  $result = mysql_query($query) or die("Error selecting books");

  //display books
  while($row = mysql_fetch_assoc($result)) {
  ?>
   <div class='book' id='book_<?php echo $row['id']; ?>'>
    <a class='edit' href='#'>edit</a>
    <h3 class='title'><?php echo $row['title']; ?></h3>
    <p><em class='genre'><?php echo $row['genre']; ?></em></p>
    <p class='description'><?php echo $row['description']; ?></p>
   </div>
  <?php
  }
  ?>
 </div>
 
 <div id='edit_dialog'>
  <form action='edit.php' method='post'>
   <input type='hidden' name='id' />

   Title: 
   <input type='text' name='title' /><br />
   
   Genre:
   <select name='genre'>
    <option value='fantasy'>Fantasy</option>
    <option value='mystery'>Mystery</option>
    <option value='nonfiction'>Nonfiction</option>
   </select><br />
   
   Description:
   <textarea name='description' cols='30' rows='3'></textarea>  
  </form>
 </div>
</body>
</html>

AJAX Form Validation

Many sites today validate form inputs as the user types. These validations are usually simple, like checking if a username is available, but contribute to a great user interface. I'm going to walk through how to do this with PHP and AJAX, and the advantages and disadvantages.

I'm going to make a simple form with two inputs, a username and a password. I'm then going to validate the inputs as the user types using 2 different methods.

Let's start with the form.

<html>
<head>
  <title>Form</title>
</head>
<body>
<form>
  Username:
  <input type='text' id='username' />
  <br />Password:
  <input type='password' id='password' />
</form>
</body>
</html>

The first field we'll validate is the password field. We'll create a validatePassword() javascript function that makes sure the password is at least 6 characters long.

<script type='text/javascript'>
function validatePassword() {
  var field = document.getElementById('password');

  var test = true;

  //If password is less than 6 characters
  if(field.value.length < test =" false;" backgroundcolor =" 'green';" backgroundcolor =" 'red';">

Now we need to add a keyup event to our password input.

<input type='password' id='password'
onKeyUp='validatePassword();' />

Now we are going to validate the username by making sure it's available. We can't do this just using javascript since we have to check a database, so we use AJAX and PHP instead. Here's the php page (validateUsername.php).

<?php
//include mysql config file
include 'mysql.php';

//get passed username
$username = $_REQUEST['username'];

//sanitize passed username
$username = mysql_real_escape_string($username);

//make sure username is not empty
if(empty($username))
  exit("false");

//query the database for matches
$query = "SELECT id FROM users WHERE username='$username'";
$return = mysql_query($query) or
  die ("Error getting matches: " . mysql_error());

//If a match exists, return false, else return true
if(mysql_num_rows($return)>0)
  echo 'false';
else
  echo 'true';
?>

If the username 'jsmith' is already taken, validateUsername.php?username=jsmith would output 'false'. Otherwise it would output 'true'. Now we need ajax to interact with this page. I'm going to use Prototype for the ajax to make the code easier to understand.

<script type='text/javascript' src='prototype-1.6.0.2.js'></script>
<script type='text/javascript'>
function validateUsername()
{
  //get username input
  var field = document.getElementById('username');

  //Don't use ajax if username is empty
  if(field.value.length == 0)
  {
    field.style.backgroundColor = 'red';
    return;
  }

  //Initialize new ajax request
  new Ajax.Request('validateUsername.php', {
    method: 'get',
    parameters: {
      username: field.value
    },
    //If a response is sent back
    onSuccess: function(transport){
      //get response text
      var response = transport.responseText;

      if(response=='true') //validation passed
        field.style.backgroundColor = 'green';
      else //validation failed
        field.style.backgroundColor = 'red';
    }
  });
}
</script>

Once again we need to add a keyup event to our input.

<input type='text' id='username'
onKeyUp='validateUsername();' />

Now we have all out parts. Before I put it all together and show you a demo, understand that validating a form with Ajax should be the last resort. The only time you should use Ajax is if you must interact with a database. Anything else is unnecessary load on your servers. I do feel, however, that using Ajax where needed is well worth the server load.

Here is a link to a demo. Below is the complete source of the html page. The php source is above.

<html>
<head>
  <title>Form</title>

  <script type='text/javascript'>
  function validatePassword() {
    var field = document.getElementById('password');

    var test = true;

    //If password is less than 6 characters
    if(field.value.length < 6)
   test = false;

    if(test) //validation passed
    {
     //Change input background green
     field.style.backgroundColor = 'green';
    }
    else  //Validation failed
    {
   //Change input background red
   field.style.backgroundColor = 'red';
    }
  }
  </script>
  <script type='text/javascript' src='prototype-1.6.0.2.js'></script>
  <script type='text/javascript'>
  function validateUsername()
  {
    //get username input
    var field = document.getElementById('username');

    //Don't use ajax if username is empty
    if(field.value.length == 0)
    {
      field.style.backgroundColor = 'red';
      return;
    }

    //Initialize new ajax request
    new Ajax.Request('validateUsername.php', {
      method: 'get',
      parameters: {
        username: field.value
      },
      //If a response is sent back
      onSuccess: function(transport){
        //get response text
        var response = transport.responseText;
 
        if(response=='true') //validation passed
          field.style.backgroundColor = 'green';
        else //validation failed
          field.style.backgroundColor = 'red';
      }
    });
  }
  </script>
</head>
<body>
<form>
  Username:
  <input type='text' id='username'
onKeyUp='validateUsername();' />
  <br />Password:
  <input type='password' id='password'
onKeyUp='validatePassword();' />
</form>
</body>
</html>