Dynamically Add Input Form Fields With jQuery

And how to deal with the data on the server-side (PHP)

A very frequent requirement from customers is to have input fields dynamically added to a form while typing in it. This should happen without refreshing the page because the user shouldn't be submitting the form before all their information is completed. Here below is a simple example of such interface:
Item quantity: Item name:

Click on the "Add Row" button and you'll see it in action. Ever wondered how to do something like this? Let me show you.

Download Working Example Here! (some fixes to the code are added inside)

The HTML

The HTML code for this is actually quite simple. It's just a form with onclick action at the "Add row" button: [sourcecode language='html']
Item quantity: Item name:
[/sourcecode]

The JavaScript (jQuery)

If you had to do this with basic Javascript, it would require lots of typing. But the jQuery's html() method takes all the browser-related hassle out of you, so you can just construct your HTML code and append it when the button is clicked: [sourcecode language='javascript'] var rowNum = 0; function addRow(frm) { rowNum ++; var row = '

Item quantity: Item name:

'; jQuery('#itemRows').append(row); frm.add_qty.value = ''; frm.add_name.value = ''; } [/sourcecode] This function simply constructs HTML code for a new row while filling the form field values from the data supplied by the form. Then it appends the code to the wrapper DIV element and cleanups the values in the original form. Cleaning up the values is good user experience practice in such cases. Otherwise the user will be confused whether the first row will be stored to the database or not. The added rows don't have another "add row" button. Instead of this they have "remove" button in case the user has added too many rows and wants to delete some of them. Here is the removeRow() function: [sourcecode language='javascript'] function removeRow(rnum) { jQuery('#rowNum'+rnum).remove(); } [/sourcecode] Now you can see why we needed to count the rows and to use that rowNum global variable. We needed unique ID on each row so it can be removed.

The Back-End (PHP) - Inserting the records

At the server-side there is a straighforward and a tricky part. I'll show you the easy one first - inserting the data. Let's assume we have a MySQL database and a very simple table called products with fields id, qty and name. So when processing the POST data we'll do something like this: [sourcecode language='php'] foreach($_POST['qty'] as $cnt => $qty) { $sql = "INSERT INTO products (qty, name) VALUES ('$qty', '".$_POST['name'][$cnt]."');"; // run the query - with mysqli_query or whatever database wrapper you are using // ... } [/sourcecode] (Please note there is no security filtering done in the query above) In case you don't understand, here's the explanation: as the field names had [], in PHP this will send $_POST array with the name of the field and the values from all form fields with this name. So we are iterating through the $_POST array 'qty' while taking the current index in $cnt. Then we use the same $cnt to match the same row value in $_POST['name']. And that's it, the data is inserted.

The Back-End (PHP) - Updating the records

This is where the things become tricky. We have several goals:
  • To let the user see and edit already inserted data
  • To let the user add new data
  • To let the user remove data
This means we have to construct some more HTML and basically break it in two parts - editing existing data and adding new data. The HTML/jQuery code for adding new data will be exactly the same as above. So let's see what can we do with the existing data: [sourcecode language='php'] // let's assume you have the product data from the DB in variable called $products foreach($products as $product):?>

Item quantity: Item name: Mark to delete

[/sourcecode] What's going on here? We are iterating through the existing DB records and displaying similar forms for them letting the user edit the data. We also add a checkbox that allows them to mark a product for deletion. All the changes will be stored after the form is submitted. Like this: [sourcecode language='php'] // first delete the records marked for deletion. Why? Because we don't want to process them in the code below if(is_array($_POST['delete_ids']) and !empty($_POST['delete_ids'])) { // you can optimize below into a single query, but let's keep it simple and clear for now: foreach($_POST['delete_ids'] as $id) { $sql = "DELETE FROM products WHERE id=$id"; // run the query - not shown } } // now, to edit the existing data, we have to select all the records in a variable. $sql="SELECT * FROM products ORDER BY id"; $products = .... // run your DB wrapper methods here to fill $products // now edit them foreach($products as $product) { // remember how we constructed the field names above? This was with the idea to access the values easy now $sql = "UPDATE products SET qty='".$_POST['qty'.$product['id']]."', name='".$_POST['name'.$product['id']]."' WHERE id='$product[id]'"; // run the query } // (feel free to optimize this so query is executed only when a product is actually changed) [/sourcecode] And after the above is done, don't forget to also add the new products with the same code as in "Inserting the records" section. That's it. Was it clear and easy?

A Few Interesting Scripts

Browsing Codecanyon I've found several ready scripts that do something like what I have described above. Have a look at them and decide yourself if some of them can do the work for you:

WatuPRO 3.6 and The Play Plugin

The Upgrade

There has been a significant upgrade of WatuPRO with several important features and bug fixes:

- Resolved conflicts with all known membership plugins - “Show results” button can be always visible on ‘one question per page’ quizzes, but warns about premature submitting. Useful for long quizzes. - Schedule exam (makes it available only in selected date ranges) - All user roles can now use the exams. The limitation to Student role caused far more issues than benefits so we decided to drop it altogether. You can still manage which roles have access to manage the tests. - You can now use WordPress User Roles instead of User Groups to avoid redundancy, and for better integration with membership plugins. - Navigation improvements - Filter test results by user role - Started developers API (see the previous post for more information)

As usual upgrade is free for users who purchased WatuPRO less than one year ago and will be delivered by a newsletter in the next few days.

The Play Plugin

Another thing to note is the new plugin called Watu PRO Play. It adds gamification element to Watu PRO and lets you assign levels and badges, allow users to redeem rewards, generates many leaderboards, and more. Just check the site for more info or email us with your questions.

WatuPRO Hooks Reference & Developers API

As WatuPRO is growing we see the need of many customers to enhance and customize it. We do provide some customization services but can't handle all of the requests. Besides, we wanted to allow third party developers and companies to extend WatuPRO and add more functionality to it. So here is the first version of the developers API. Please consider this page work in progress, as is the API itself. We are starting with just a few basic function calls. More will be added and documented with the time. For simplicity the API itself will use the same version number as the plugin.

WatuPRO API Version 3.6

Main Concept

WatuPRO API uses WordPress do_action calls to create custom actions. This means that in order to add custom functionality you need to use add_action() to call your custom functions. Any custom parameters passed to do_action will be shown below.

Barebone Custom Plugin

We have created a "barebone" custom plugin that will help you with the initial setup for your custom work. Download the plugin here: watupro-custom

Available actions

do_action('watupro_completed_exam', $taking_id) - called when test is completed. Passes the current completed exam record ID. do_action('watupro_completed_exam_edited', $taking_id) - called when admin/teacher edits user's details. This option is enabled by the "Manual grading" feature in the Intelligence module. Passes the ID of the taken exam record. do_action('watupro_my_certificates') - this call is at the bottom of the "My certificates" page. The action passes no parameters but you can get the current user ID as a global. This action is already used by the Play Plugin. do_action('watupro_select_show_exam', $exam) - called when displaying the exam on the screen, and prior to any permission checks. Passes the exam object and allows you to do something with it. do_action('watupro_admin_menu') - lets you hook a custom page under watupro admin menu. Use 'watupro_exams' as parent. do_action('watupro_user_menu') - lets you hook a custom page under watupro user dashboard menu. Use 'my_watupro_exams' as parent. do_action('watupro_show_exam_js', $exam) - lets you plug your custom javascript in the quiz itself. Passes the $exam object. Available Filters We have started adding some filters too: apply_filters( 'watupro_filter_view_show_exam', $show_exam_view, $exam); - called right before showing the quiz. You can use it to load your custom show_exam view. We recommend to still include our view (views/show_exam.php) and use it only to do something before or after it. apply_filters( 'watu_filter_current_question_text', $current_text, $qct, $question_content, $correct ) - called after a question has been processed so you can modify the way it's displayed on the final screen and live result. The following filters allow you to modify the content of the emails sent to admin or quiz taker when a quiz is completed: $output = apply_filters('watupro-email-results-taker', $output, $taking_id); $output = apply_filters('watupro-email-results-admin', $output, $taking_id); The following filter allows you to modify the content of user uploaded files: $contents = apply_filters('watupro-user-file-uploaded', $contents, $question_id, $detail_id, $taking_id); $achieved = apply_filters('watupro-achieved-points', $achieved, $taking_id); - allows third party plugins to modify number of points The following filter is applied on calculating quiz grade: watupro_calculate_grade -it's more complicated so it's documented separately here. Expect a lot more actions to be added in the next versions of Watu PRO.