Wednesday, January 21, 2009

Super Simple AJAX Forms with jQuery and JSON : webpage.html

In this installment of the super simple AJAX forms with jQuery we look at the webpage.html file. This is a pretty simple HTML file all things considered.  The key components of this HTML file are the .changed style in the header, the form (called testForm) and the block of javascript code at the bottom.  We'll take a look at each of these parts.  You can download the entire set of source code and following along.

CSS Style
<br /> <style><br />  /* apply specific formatting for changed fields */<br />  .changed{<br />   background-color:yellow;<br />  }<br /> </style><br />
The CSS style here outlines the effect applied to the input boxes when they have been changed. We name it changed so you can clearly see how e apply this style and use it as a flag to determine what changes need to be posted to the server. This is really a nice feature of this example. I see far too often entire records updated when just a single field is changed. That or complex PHP code is used to compare what is currently in the database.

The Form
<br /> <form id="testForm"><br />  name: <input type="text" id="FLD_name" class="inputfield" onchange="$(this).addClass('changed')"><br /><br />  mail: <input type="text" id="FLD_mail" class="inputfield" onchange="$(this).addClass('changed')"><br /><br />  <input type="hidden" id="FLD_uid"><br />  <input type="button" onclick="submitChanges('testForm')" value="Submit Changes"><br /> </form><br />

This form is nothing special for the most part. The key items to look at here are the ID names contain a FLD_ prefix. We do this so we can identify in the PHP code which elements are "fields" that need to be processed. In the PHP code we read ALL the data sent and filter out just what we need. So having a unique identifier is critical to make sure our posting of data with MySQL doesnt fail. The onchange attribute is used to apply the "changed" class with jQuery when the field changes. This means that unless someone changes the data, it won't be flagged as an item to update. I added an inputfield class here so you can see that you can have multiple CSS classes applied. The last item to note is that we have an input button with a method call to submitChanges. We pass the form ID name along with it. This is done so you can use the same code regardless of the number of forms. So with this you are not building form specific code, youre writing a very re-usable element.

The Javascript
 <br />  // Function to handle the submission of changed <br />  // only fields on the form we want (multiple form support)<br />  function submitChanges(formName){<br />   // Build list of changed variables<br />   var queryString="";<br />   $('#'+formName+' .changed').each(function(){<br />    // Add new varialbe for each "Changed" item<br />    queryString+="&""="+this.value;<br />   });<br />   if(queryString==""){<br />    alert("Nothing changed on the form");<br />    return;<br />   }<br />   queryString+="&id="+$('#FLD_uid').val(); // Add ID number<br /><br />   // Send Data, get reply<br />   $.getJSON("dataservice.php?action=update"+queryString,function(data){<br />    // Display Message on errors<br />    if(data.status!="OK"){<br />     alert(data.status);<br />    }else{<br />     // Remove Changed Attribute on success<br />     $('#'+formName+' .changed').each(function(){<br />      $('#''changed');<br />     });<br />    }<br />   });<br />  }<br />  // Sample, get 1 row of data from database<br />  $(document).ready(function(){<br />   $.getJSON("dataservice.php?action=getuser&id=2",function(data){<br />    // find fields we have data for, regardless of form.<br />    for(var key in data[0]){<br />         $('#FLD_'+key).val(eval('data[0].'+key));<br />       }<br />   });<br />  });<br />

Finally this is where all the work is done. It is not a large amount of code so it should be easy to follow along. There are 2 items here. The first is "submitChanges" the second is the jQuery "ready()" function. We'll talk about the $(document).ready() at the bottom first.

Once the page loads, jQuery fires a ready method to run some code. We use jQuery $.getJSON to talk to our dataservice.php and pull down 1 record from our users database. You can see here we pass an action of "getuser", and the "id" of 2 which matches the id number in the database. You'll see this is clear by looking at the dataservice.php.

Once we pull this data down, we iterate the "keys" of the JSON data, then using javascript eval() function, we grab the data and post it to any matching #FLD_ on the form. So for example, if the JSON contains a "name" key {name:'Smith'} in the JSON, we map it to #FLD_name. We do this for a few reasons. First, we introduce some logical consistency into how we use our database. This pulls down a database field name, and we use the same field name in our form. We get away from problems like a database field called first_name and a form field name called userFirstName. Later on you'll thank yourself in keeping things consistent and searchable. We also do this to save time mapping data. Since we use the same name (with just a prefix added) its easy to do this programatically vs. having to do a lot of formField=dataFieldValue in the code. Less code for everyone. So this function is pretty simple, pull down the data, map it into the input fields by name.

Now we move onto the submitChanges method. Really, this looks more daunting that it really is. There is a very limited amount of code here I commented it well so you can see just what you would want to change in your own application

We first set an empty queryString which will be used to send the changed data to the dataservice.php. We next tell jQuery to find all the .changed class items in the particular form we just passed. If that code is a little unclear here is what the expression would look like hardcoded.

$('#testForm .changed').each()

Now, lets just talk about what we asked jQuery to iterate through. We said find the ID "testForm" then, find all tags with the "changed" CSS class applied. Then, we ask jQuery to iterate through it with the .each() function. This exposes each tag to us one at a time so we can use it to build our queryString.

queryString is built, or it's not based on each changed item. We pull out the FLD_ names of changed data, apply it to the queryString forming something like


Should we not have any changed data, queryString wont have anything in it and we'll tell the user that nothing changed on the form. If data changes do need to be posted we skip that IF statement, add the "id" of the record manually and prepare for our posting back to dataservice.php. NOTE: The ID is the only hard coded field form element. "FLD_uid" is a unique key in the database that allows you to map it back to the right element. You don't necessarily have to do it this way. Alternatively you could hard code "changed" as a class to it, and it would always be picked up. The down side to this is that if there is no changed data you'll fire an empty query. I also like hard coding the ID number because as a primary key of a DB you should always have it. This type of code ensures I don't forget it.

Next, we call our $.getJSON again, we tell it the action is to update, and append on our queryString. This is posted to the server and we wait for the response asynchronously. Once we receive it, if it's not OK we return the server message. Finally if everythig is good, we pull off all the "changed" values.

You can see here we have some very streamlined code, and not much of it. Adding more form fields requires no changes to our javascript. We can basically include this into a .js file and stamp it on any form we want. A little tweaking and we could make it work for multiple databases as well. You get the idea.

Next, we'll talk about the dataservice.php in detail.

No comments: