Easy form population with jQuery and the Populate plugin

Difficulty: Easy

A brief overview of the problem

The massive explosion in web applications over the past few years means that more and more data than ever is being saved and loaded from databases. Web application frameworks such as Kohana take a lot of the grunt-work out of the process of shunting data around, but there are still areas where manual work needs to be done.

One of these areas is in HTML form views, where you’re echoing your data back from the database into form fields such as text boxes, radio buttons and dropdowns.

Of course there are various ways to make this easier, most of which involve some level of automation, but all of which involve writing more, not less, PHP code.

So what if I told you you could populate any HTML form from your models with:

  • One single line of PHP code?
  • One single line of JavaScript code?
  • And you kept your HTML forms 100% clear of PHP?

Introducing jQuery

If you haven’t already heard of jQuery, briefly it’s one of the most elegant and powerful JavaScript frameworks out there.

On top of all this, it’s massively flexible as it has been designed to allow developers to plug into it, and transparently call their own methods, or complete modules, as if they were part of the main framework.

I’ve written a couple of plugins for jQuery so far, one of which I’m going to tell you about now.

Introducing the Populate plugin for jQuery

I designed Populate to populate a form (clever naming, huh?) using data supplied in the JSON format.

You don’t need to worry too much now what JSON is, save to say that it’s a way of representing complex data (for example, form data…) in string format, and both JavaScript and PHP5 natively support it. Imagine JSON as XML on a massive, MASSIVE crash diet.

A fuller explanation of how JSON works along with some code examples are available on the Populate demo page.

Anyway… back to the plugin – how does it work?

Well, as you might expect, it works on the client-side, in JavaScript.

From PHP you basically hand the form data to Populate in the special JSON format, tell it which form you want populated and the next thing you know, the form is populated!

It’s literally that simple.

Internally, Populate takes the data and iterates over the form, and when it finds a key that matches a form-field name, it runs an element-specific function to give it the correct value(s), whether it be a textfield, dropdown, radiobutton or checkbox array, multi-select, you name it (if you find an example where it doesn’t work – let me know and I’ll fix it!).

And the best thing about it? Because JavaScript is doing all the hard work – your HTML forms (your View files) are kept clear of PHP, which makes changing them or updating them much less hassle. Bliss!

The only caveat I haven’t mentioned so far is that your form names and data keys need to be named identically (but you’d probably figured / are doing that already). For hierarchical data, you just need to follow standard hierarchical PHP naming conventions in your form, again full details of which are available on the the Populate demo page.

OK Dave, I’m up to speed on JavaScript now… how do I use it!?

Well, dear Reader, the basic principle is this:

  • Include both the jQuery and Populate scripts in the head of your page
  • Get your model’s data as a JSON string
  • Call the jQuery Populate plugin with the said JSON string after your form has fully output

Let’s see that in code, shall we?

(As with my last tutorial, the code is actually very simple – I’m just explaining each step, every step of the way so you get a good understanding of what is actually happening, and why it is actually happening)

First of all, the PHP in your view’s Controller class:

So, you’ve pulled out some data from your model, and it’s in an object or associative array named $data, for example:

$data = array
(
	'name' => 'Dave Stewart',
	'city' => 'London',
	'url' => 'www.davestewart.co.uk'
)

.
That’s good. PHP understands that, but we need to get it into a format that JavaScript understands, namely the magical JSON format. So let’s use a native PHP5 function, json_encode():

$json = json_encode($data);

.
This will result in a string that looks like this:

"{'name':'Dave Stewart', 'city':'London', 'url':'www.davestewart.co.uk'}"

.
Next up is the PHP / JavaScript for your view file…

So, now you have the data in a format that JavaScript can understand, we just need to to hand it to your view, straight into the JavaScript statement that calls Populate (which must come after your form) :

$("#myform").populate(<?php echo $json; ?>);

.
To explain that statement, let’s break it down:

  • The first bit, $ (a single dollar sign) is the reference to the main jQuery function
  • The next bit (”#myform”) tells the jQuery function that you want to reference the form on the page with the id “myform” (note the # – this is CSS syntax to reference an id)
  • The third bit .populate is the chained call to the actual populate() function
  • And the last bit (everything between the brackets) is the argument passed to the populate function.

One thing to note is that there are NO QUOTES around the PHP echo in the HTML, as JavaScript reads it in natively as an object and NOT a string.

Anyway – that will result in something like this being written to the page:

$("#myform").populate({'name':'Dave Stewart', 'city':'London', 'url':'www.davestewart.co.uk'});

.

And literally – that’s it!

As soon as the JavaScript on the page executes, jQuery will find the form, run the populate plugin, hand it the JSON data, and Populate will go through the form, matching up the keys and values from the data and your form is populated.

Conclusion

With a little bit of JavaScript you can completely do away with muddy forms, endless changes and mixing of processing and presentation within your view files.

It’s easy, simple, and clean – and as long as you can be sure your clients are using JavaScript, effective.

This last point is perhaps understandably where it’s a make-or-break for some developers, and after having various Kohana members check out the tute, some interesting discussion started on the Kohana forum, with various opinions and other ways to skin the cat presented, which is definitely worth reading.

My thoughts are that this is still a pretty nifty way to do things, but the assumption of JavaScript being present could cause a problem for some. However, if you’re getting a site up and running quickly, this method really can’t be beaten for speed, so if…

  • you’re prototyping
  • you’re still in Beta
  • your application is in a state of flux
  • or you can be sure that an extremely high percentage of your users won’t be turned away

…it can definitely help with quicker, easier and more flexible development.

Demo and Download

Check out multiple demoes and download the plugin from Keyframes and Code.

Thanks for reading,

Dave

A bit about me…

I’ve been a web developer for about 6 years now (moving over from 3D animation) specialising in ActionScript, PHP, HTML, JavaScript and CSS, with supporting roles played by XML and SQL.

My portfolio site is at www.davestewart.co.uk and my development site is at www.keyframesandcode.com.


22 Responses to “Easy form population with jQuery and the Populate plugin”

  1. Alessandro Frangioni Says:

    Dave, it’s more simple getting it working than explaining how it works. Awesome!

  2. Geert Says:

    Not that I want to ruin the party, but I definitely would lose sleep over the fact that you are relying on javascript for such crucial functionality. You mentioned that in the conclusion already. Just wanted to point it out again.

    What about special HTML characters? Do you need to apply html::specialchars() to the POST values yourself first, or does the Populate plugin take care of that for you?

  3. James Says:

    Hi, I found your blog on this new directory of WordPress Blogs at blackhatbootcamp.com/listofwordpressblogs. I dont know how your blog came up, must have been a typo, i duno. Anyways, I just clicked it and here I am. Your blog looks good. Have a nice day. James.

  4. Dave Says:

    Nice tutorial. It may be worth mentioning that you need to run $(”#myform”).populate() after the form html has loaded. This is best done by wrapping it in jQuery’s document ready function like so:


    $(function(){
    $("#myform").populate(<?php echo $json; ?>);
    });

    On another note, the acronym PHP actually stands for “PHP: Hypertext Preprocessor”.

  5. Dave Stewart Says:

    Thanks for the views everyone, especially to those who commented in the Kohana Forum.

    I’ve updated the conclusion at the end to point of out some of the weaknesses in this approach, and where it might be better to use the more traditional approach of mixing up your HTML and PHP.

    Cheers,
    Dave

  6. Cristiano Betta Says:

    Guys, GUYS! This is a such a bad solution to something that should definitely not be handled in JS!

    For F sake just make it that the form helpers can take a model object and prefill the form, and when a form submission fails do the same with the non-saved model.

  7. cwxwwwxdfvwwxwx Says:

    well, hi admin adn people nice forum indeed. how’s life? hope it’s introduce branch ;)

  8. Zbyszek Says:

    Great idea! But I think that it has only one (but a big one) flaw: what if user doesn’t have JS?

    It’s good for web applications that are used internally in some company or for paid pages or web applications that cannot be used without a javascript from definition but give some great functionality that user will want to use – because there user needs functionality and he/she is ready to adapt (change browser or turn on JS for example).

    But for normal web page it isn’t good. User will be angry that page doesn’t work – more angry if there is no explanation why should he need to change browser or turn on javascript (and there are some places that javascript is turned off by admins – for example in some companies, in work).
    But I think it can be changed. Just need to write some code that will recognize if user does have JS and for those users there should be “normal” view available. But it would be overkill to write standard form and populated one.

    But maybe if one loads subpages by AJAX one can construct some population method that for view loaded by AJAX will use JSON format and jQuery and for pages loaded in standard way will use standard way of doing it (tags).
    When creating a web application with PHP I often create two methods in controller for each view – one for loading entire page (with headers, content and footer) and one for loading only content. And I create a menu that is navigable normally when there is no JavaScript and by AJAX when there is (with jQuery you can remove normal browser click action that moves to another URL and bind AJAX one).

  9. Old man Says:

    Just to clarify one comment.

    —-On another note, the acronym PHP actually stands for “PHP: Hypertext Preprocessor”.—-

    This is wrong. The original acronym was for “Pretty Home Page”.

    PHP, or Pretty-Home-Page, started as as a CGI script written in Perl.
    Gradually, it became a language itself, dedicated to server-side
    programing. It essentially is a outgrowth of a hack in the unix
    tradition. (e.g. c/tcsh, sh/bash, sed/awk/perl)

    Not many people had “websites” then. They had “homepages”. PHP was a way to give the ability to dynamicly generate your page with different information instead of the static html pages everyone else had. Thus making them “pretty”.

  10. Old man Says:

    Oh, BTW, the problem I see with your method is that a form reset button won’t work. It would blank the form. That is unless you bind any reset buttons in the form to a “repopulate” function.

    Did you?

    Well, just checked your code, and you did not. :(

    I would suggest you add another argument to your main funtion that either:

    1) allows the person to identify all reset buttons and bind a repopulate function to thier click,

    or even better

    2) have a flag and if set, you search the form for all buttons with attribute “type” equal to “reset” and bind the repopulate function to them automagicly.

    Good idea though.

  11. cg Says:

    I think this things seems good for websites that would require javascript anyway, but for most websites it wouldn’t be good to force users to use javascript just for form population.

    Oh, and php used to stand for Pretty Home Page, it doesn’t anymore. It stands for PHP: Hypertext Preprocessor. And if you don’t believe me you can check their website. It says it’s recursive, so the PHP in PHP: Hypertext Preprocessor also stands for PHP: Hypertext Preprocessor, and so on and so forth.
    (just a side-issue)

  12. dudeguy Says:

    It’s ok to have a comment.

  13. Riu Says:

    Ok. All it’s good, but tell me – why this site powered by WordPress?… why it isn’t any blog aplication with Kohana?

  14. ollopa Says:

    Wow, the critics and the haters have spoken.

    I agree that this method has its drawbacks for general use, but there are times when we are willing to sacrifice compatibility for slickness. Fore sites that will be heavily AJAX dependent, I personally think that this is a novel and useful way to handle form population and submission. I’d never heard of JSON before ;)

  15. Marcelo Rodrigo Says:

    Site abandoned? :(

  16. Oliver Kiss Says:

    Nice examples. Helped me a lot.

  17. Steven Says:

    I’m trying, but without much luck. This is my script in “myScript.js”.
    This is triggered when I click a table row:

    jQuery.post(”get_storeData.php”, { storeID: this.cells[0].innerHTML },
    function(data){
    jQuery(”#store_data_form”).populate();
    }, “json”);
    });

    But my Firebug gives me the following error:
    jQuery(”#store_data_form”).populate is not a function.

    Yes, I have included the populate library:

    What am I doing wrong?

    Oh, I have no problem using alert(data[0].name) for example.

  18. lol Says:

    LOL THAT IS SO GREAT

    OH WAIT I HAVE JAVASCRIPT DEACTIVATED ROFLCAKES

  19. sn0rcha Says:

    if you don’t have javascript in the year 2009 get off the web.

  20. David Says:

    Getting an issue here.

    code:

    Product Name

    $(function(){
    $(”#update_product”).populate({”productId”:”1″,”productName”:”T-Shirt”});
    });

    getting the error ‘object expected’ whats going on?

  21. Kevin Says:

    Dave, get rid of the quotes around the field names in your brackets, that may do the trick.

    $(function(){
    $(”#update_product”).populate({productId:”1″,productName:”T-Shirt”});
    });

    On a side note, I’m doing something similar in an admin page I’m creating from scratch (I JUST started getting into Kohana) that you may be interested in, or may hate me forever for. I’ve just recently decided to venture into the server-side languages and mostly have experience with Flash/ActionScript with a minor in HTML, CSS, and JS… so the client-side part of the world.

    That being said, I’m a big fan of JQuery and the way it makes everything SO much easier, but I still find it to slow things down sometimes, so I try to keep javascript involvement to on-demand only if possible. I came up with a way to minimize the overhead both on the client’s system when the page is loaded, and client/server load when the form fields are posted.

    When the page first loads, php code builds the form which has a table in it that has 6 columns, and then one row for every entry in the table. 5 of the columns match the fields name and values from the table, but the 6th column contains the following:

    This creates a checkbox in a column called “Modify” that the user can click to make the data in the table available to be changed. The “8″ that is passed to the modifyform function was populated by php using the $id field for that entry from the table, which is an auto increment number. I should also mention that each of the 6 fields have ID=”colname$id”. So one of the TD fields that is in the same row as the above link is:

    something.jpg

    The modifyform function accepts the passed number in a field named “IDnum” and basically does the following for each of the fields:

    $(”#imagesrc”+IDnum).html(”");

    This replaces the inner html of , which was just text, with a form text field where the name is “data8[src]” and the value is “something.jpg”. The rest of the td fields are given form fields that are named “data8[something]“. This includes the td field that had the modify checkbox, which is replaced with a hidden field “” to be used with my WHERE parameter when I update the table.

    In conclusion, this provides 4 benefits:

    1) It keeps Sneazy Sue from accidently changing 15 fields in the blink of an eye since she has to click on the checkbox to be given access to the data

    2) It minimizes the information that is posted on submit because it’s only transmitting the fields that the user modified instead of every single field, giving us a break with the resources required to process everything

    3) It puts the posted data into nice neat arrays by entry to make additional functionality a lot easier, as Mr Stewart mentioned

    4) It would be just as easy to insert a table row into the html just below the row that had the modify checkbox that was clicked which would match what I’m currently altering the td fields to be now, and then change the css display attribute for the clicked TR to be “none”. This would hide the original row instead of permanently changing it, which means it would be a snap to have another JS function delete all rows with input fields and unhide all original rows when a “reset” button is pushed.

    That’s all. Hooray. Sorry for the super long entry. It’s my first one, cut me some slack :) If you want to see this in action, check out my work in progress at http://www.kevinheidt.com/phptest/testphp.php (sorry for the ugly, I’ll clean it up when it’s done)

  22. Kevin Says:

    Holy Moly that stripped out a bit of my code examples. Ok, I’ll use ^ for double quotes and ~ for single quotes.

    After [but the 6th column contains the following] should be:

    [something.jpg] should be:
    something.jpg

    [$(#imagesrc+IDnum...] should be:
    $(^#imagesrc^+IDnum).html(^^)

    Sorry about that, friends. Hopefully this one works better. If not, I give up.