Hi there,

I was after some guidance on how to integrate JQuery once a form has been submitted. I have a form for which this is the submission function:

  function nl_sub_form_submit($form_id, $form_values) {
  simplenews_subscribe_user($form_values['email'], '1285', $confirm = TRUE);
	
  drupal_goto('http://www.example.com/thanks-for-subscribing');
}

So basically it subcribes the email address to the newsletter and then re-directs to a thank you page. How can I Ajax this up a little, and re-load only the content in the block to give a thank you message?

Thanks so much for your help,

Neil

Comments

manesh’s picture

I am looking to do the same type of thing!

therealwebguy’s picture

Using jquery you can intercept the form submission easily, grab the data from the form and then pass it on via ajax to handle the form submission. Here is how you would go about doing that:

Step 1. You need to create the js file that you are going to use. For now, we'll assume its in your custom build module called "mymodule/form.js".

$(document).ready(function(){
  $('form#mymodule-custom-form').submit(function() {
    // At this poing, grab all of your form values that you would like to 
    // pass on. For example:
    var first_name = $('input#edit-first-name').val();
    var last_name = $('input#edit-last-name').val();

    // Once you have all of your variables set up, you can proceed to 
    // handle the ajax. You'll need to do your own research on ajax with jquery
    // for more advanced features, but I'll give you a simple example here:
    $.ajax({
      type: "POST",
      url: "/thepath/to/a/menu/callback",
      data: "first_name=" + first_name + "&last_name=" + last_name,
      success: function(msg){
        //msg will contain any content that has been printed to the
        // screen, so you can use your url callback function to print
        // that you would like to user here, if any.
      }
    return false;
  });
});

Ok, now that our .js file is all set up, lets look at the mymodule.module file which is going to contain the form people can fill out.

<?php
function mymodule_custom_form() {
  $form = array();
  $form['first_name'] = array(
    '#type' => 'textfield',
    '#title' => t('First Name'),
    '#required' => TRUE,
    '#type' => MENU_CALLBACK,
    );
  $form['last_name'] = array(
    '#type' => 'textfield',
    '#title' => t('Last Name'),
    '#required' => TRUE,
    '#type' => MENU_CALLBACK,
    );
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Send the Form'),
    );
  return $form;
}
?>

And now lastly, make a theme function which will display everything you want on the page, including the form. The most important part of this is to make sure that the .js file gets included so that when you submit the form, the js will be activated.

<?php
function theme_mymodule_custom_form() {
  drupal_add_js(drupal_get_path('module', 'mymodule') .'/form.js');
  $output = '<h1>Welcome to the page with cool ajax form!</h1>';
  $output.= drupal_get_form('mymodule_custom_form');
  return $output;
}
?>

This is the basic overview of how you would accomplish what you are looking to do. I typed this super quick so I apologize ahead of time of I tyoed any coding errors, but this should get you on the right path pretty quickly. If anyone caches errors I've made they can leave comments after me and clean it up. =)

Keep it up guys! Happy programming!

jeanpierre’s picture

Hello,
This very simple example was very usefull to me !
I think there was this missing :
});
after
return false
Thanks ;)

therealwebguy’s picture

Yes, there needs to be one more }); in there, glad you caught you that. =) Cheers

Alexander Matveev’s picture

You must use form tokens, or I can POST millions of spam POSTs to your callback directly.

ncameron’s picture

You're a prince and a gentleman! Thanks for taking the time to explain that, really appreciate it, I look forward to trying it on my next site.

Cheers,

Neil

petrellis’s picture

Hi there,

I am trying to understand how could i dynamicaly submit a form and take back the results without a page refresh. I created a really simple module which makes an addition of two numbers. I named the module addition and created two files.

addition.info
--------------

; $Id$
name = "addition"
description = "Makes an addtion with two numbers."
core = 6.x

addition.module
------------------

// $Id: $

function addition_menu () {
  $items = array ();
  $items ['add'] = array (
    'title' => t('Make an Addition'),
    'page callback' => 'add_page',
    'access arguments' => array('access content'),
    'type' => MENU_SUGGESTED_ITEM,    
  );  
  return $items;
}



/**
 * page callback created in the Implementation of hook_menu
 *
 */
function add_page () {
	$output = '';
	$output .= drupal_get_form('add_form');
	if( $_SESSION['number1'] && $_SESSION['number2'] && $_SESSION['sum'] ) {
		$number1 = $_SESSION['number1'];  
		$number2 = $_SESSION['number2'];  
		$sum = $_SESSION['sum'];
		
		$output .= $number1 . ' + ' . $number2 . ' = ' . $sum;
		unset( $_SESSION['number1'] );
		unset( $_SESSION['number2'] );
		unset( $_SESSION['sum'] );
	}  
	return $output;
}



/**
 * Creating the actual form itself happens here
 *
 */
function add_form ($form_state) {

    $form = array();
  
    //make a texfield
    $form['number1'] = array (
      '#type' => 'textfield',
      '#title' => t('Please enter number1'),
      '#size' => 10, 
      '#required' => TRUE,
    );
  
    //make a texfield
    $form['number2'] = array (
      '#type' => 'textfield',
      '#title' => t('Please enter number2'),
      '#size' => 10,
      '#required' => TRUE,
    );
  
    //a "submit" button
    $form['submit'] = array (
      '#type' => 'submit',
      '#value' => t('Addition'),  
    );
  
    // If you forget this line your form will never exist
    $output = 'Help';
    return $form;
}


/**
 * Validation function, only users who input both numbers are able to submit the form

 *
 */
function add_form_validate ($form_id, &$form_state) {
  $number1 = $form_state['values']['number1'];  
  $number2 = $form_state['values']['number2'];  

  if (!$number1 || !$number2) {
    form_set_error('numbers', t('You must input both numbers.'));
  }
}

/**
 * form_submit function, once the form passes the validation (above) this runs
 *
 */
function add_form_submit ($form_id, &$form_state) {
  $number1 = $form_state['values']['number1'];
  $number2 = $form_state['values']['number2'];
  $_SESSION['number1'] = $number1;
  $_SESSION['number2'] = $number2;
  $sum = $number1 + $number2;
  $_SESSION['sum'] = $sum;
  $output = t('The addition of ');
  // check_plain() makes sure there's nothing nasty going on in the text written by the user.
  // http://api.drupal.org/api/function/check_plain
  $output .= check_plain($number1);
  $output .= t(' and ');
  $output .= check_plain($number2);
  $output .= t(' is ');
  $output .= $sum;

  drupal_set_message($output);
  
}

This example works great but after the submition there is a page refresh and the results are displayed there. How could i do the same without the page refresh. As i have find out till now i need a .js file like the one that nrussell posted here and a call with drupal_add_js but i don't understand exactly the way... Could somebody help me with that?

Thanks in advance...

therealwebguy’s picture

Basically you are going to do the same thing I explained earlier in this thread. You might want to consider moving out of the $_SESSIONS super global as well and use drupals built in variabale_get and variable_set methods sense the data you are storing does not need to live for any specific session.

Ok so moving on. Lets take a look at the jquery that I posted.

$(document).ready(function(){
  $('form#mymodule-custom-form').submit(function() {
    // At this poing, grab all of your form values that you would like to
    // pass on. For example:
    var first_name = $('input#edit-first-name').val();
    var last_name = $('input#edit-last-name').val();

    // Once you have all of your variables set up, you can proceed to
    // handle the ajax. You'll need to do your own research on ajax with jquery
    // for more advanced features, but I'll give you a simple example here:
    $.ajax({
      type: "POST",
      url: "/thepath/to/a/menu/callback",
      data: "first_name=" + first_name + "&last_name=" + last_name,
      success: function(msg){
        //msg will contain any content that has been printed to the
        // screen, so you can use your url callback function to print
        // that you would like to user here, if any.
      }
    });
    return false;
  });
});

The url: inside this $.ajax call is a very important item that needs to be set. It is what your module is going to depend on to know which function to call based on your menu hook system. So after looking at what you have set up, this is your menu hook function currently:

<?php
function addition_menu () {
  $items = array ();
  $items ['add'] = array (
    'title' => t('Make an Addition'),
    'page callback' => 'add_page',
    'access arguments' => array('access content'),
    'type' => MENU_SUGGESTED_ITEM,   
  ); 
  return $items;
}
?>

We need to add one more menu item to validate the ajax callback.

<?php
function addition_menu () {
  $items = array ();
  $items ['add'] = array (
    'title' => t('Make an Addition'),
    'page callback' => 'add_page',
    'access arguments' => array('access content'),
    'type' => MENU_SUGGESTED_ITEM,   
  );

  $items['add-ajax'] = array (
    'page callback' => 'add_ajax',
    'access arguments' => array('access content'),
    'type' => MENU_CALLBACK,   
  );
  return $items;
}
?>

What this tells us is that the url /add-ajax is going to trigger the callback to the function add_ajax. So we need to update our jquery and make the URL point to "/add". Also, you need to update the jquery to point to your form. Sense the name of your form is add_form, the ID that drupal is going to render (unless you specify one specifically) is going to be add-form. So this would be your updated jquery:

$(document).ready(function(){
  $('form#add-form').submit(function() {
    // Grab the values of the two numbers you are going to work with.

    var number1 = $('input#edit-number1').val();
    var number2 = $('input#edit-number2').val();

    // Now that you have your variables, you need to trigger the 
    // ajax call to the url you want, in our case /add.
    $.ajax({
      type: "POST",
      url: "/add-ajax",
      data: "number1=" + number1 + "&number2=" + number2,
      success: function(msg){
        //msg will contain any content that has been printed to the
        // screen, so you can use your url callback function to print
        // that you would like to user here, if any.
      }
    });
    return false;
  });
});

Lets break this down. The new js file triggers an action on the submit of the form with the ID of "add-form". When that submit happens, we grab the two input field values number1 and number2 and pass them on the url /add in the $_POST super global. Now the next part. How do we handle / obtain this data? It all comes back to our menu hook when we added the new path to add-ajax. This is going to get called when the ajax sends its request and its going to call the function add_ajax. So lets add that now.

<?php
/**
 * Ajax callback function
 */
function add_ajax() {
  // You obtain your values through $_POST here. $_REQUEST would work
  // also, but do to possible security risks if you end of doing database layer abstraction
  // from this data, stick with $_POST.
  $number1 = $_POST['number1'];
  $number2 = $_POST['number2'];
  $sum = $number1 + $number2;

  $output = '';
  if ($number1 && $number2 && $sum ) {
    $output .= $number1 . ' + ' . $number2 . ' = ' . $sum;
  }

  // There are a couple options here at this point. Do you want to display this $output back to the user?
  // If so, you need to do a print from here so our ajax function knows about it and can push it into
  // an HTML element to display to the user
  print $output;
}
?>

I am not going to go too much further into this situation, but what we just did was handle all the math needed for the ajax callback. The print function will be available in your ajax success: option in the (msg) variable. So, in your ajax you could check to see that msg is not equal to '' and then write the results to a div that you have available in the markup.

Hope this helps everyone. I wrote this early with no double check of my work so please forgive me if there are code typoes or errors. This is more of a reference to get you on the right path.

Laters.

petrellis’s picture

Hello again to everybody from beautiful Greece,

Thanks to the help of nrussell and the guidance of one of my co-workers ( manolism ) i finally found out the way to handle all the proccessing around the form submition with and without ajax. At the next lines i am going to demonstrate how can we create a simple module which creates a block with a form which makes an addition of two numbers. I am going to show you the way that this can be happened without ajax submition at the beggining and with ajax submition afterwards which means that we are going to do exactly the same but without the page refresh. So follow me and i hope that i am going to help developers who will try to do the same in the future...

First things first. We will create a module which we will call simpleadd. This module will be a really simple module which will create a block in which will happen a simple addition of two numbers. So let's make it reality:

simpleadd.info
--------------


; $Id$
name = "simpleadd"
description = "Makes a simple addition with two numbers in a block."
core = 6.x 

simpleadd.module
-----------------


// $Id: $


/** 
 * Implementation of hook_block() 
 */ 
function simpleadd_block($op='list', $delta=0, $edit=array()) { 
  switch ($op) { 
    case 'list': 
      $blocks[0]['info'] = t('Simple Addition'); 
      return $blocks; 
    case 'view': 
      switch ($delta) {
        case 0:
          $blocks['subject'] = t('Simple Addition');
		  $output ='';
		  $output .= drupal_get_form('simpleadd_form');
		  $simpleadd_number1 = variable_get('simpleadd_number1','');
		  $simpleadd_number2 = variable_get('simpleadd_number2','');
		  $simpleadd_sum = variable_get('simpleadd_sum','');
	      if( $simpleadd_number1 && $simpleadd_number2 && $simpleadd_sum ) {
		    $output .= 'Result: ' . $simpleadd_number1 . ' + ' . $simpleadd_number2 . ' = ' . $simpleadd_sum;
	      }
		  $blocks['content'] = $output;
       	  
		  return $blocks; 
      }
  } 
} 


/**
 * Form Creation
 *
 */
function simpleadd_form ($form_state) {

    $form = array();
  
    $form['simpleadd_number1'] = array (
      '#type' => 'textfield',
      '#title' => t('Please enter number1'),
      '#size' => 10, 
      '#required' => TRUE,
    );
  
    $form['simpleadd_number2'] = array (
      '#type' => 'textfield',
      '#title' => t('Please enter number2'),
      '#size' => 10,
      '#required' => TRUE,
    );
  
    $form['submit'] = array (
      '#type' => 'submit',
      '#value' => t('Simple Addition'),  
    );
	
    return $form;
}


/**
 * Validation function, only users who input both numbers are able to submit the form
 * 
 */
function simpleadd_form_validate ($form_id, &$form_state) {
  $simpleadd_number1 = $form_state['values']['simpleadd_number1'];  
  $simpleadd_number2 = $form_state['values']['simpleadd_number2'];  

  if ( !$simpleadd_number1 || !$simpleadd_number2 ) {
    form_set_error('numbers', t('You must input both numbers.'));
  }
}

/**
 * form_submit function, once the form passes the validation (above) this runs
 * 
 */
function simpleadd_form_submit ($form_id, &$form_state) {
  $simpleadd_number1 = $form_state['values']['simpleadd_number1'];
  $simpleadd_number2 = $form_state['values']['simpleadd_number2'];
  variable_set('simpleadd_number1', $simpleadd_number1);
  variable_set('simpleadd_number2', $simpleadd_number2);
  $simpleadd_sum = $simpleadd_number1 + $simpleadd_number2;
  variable_set('simpleadd_sum', $simpleadd_sum);
}

So our simpleadd module is ready. Just activate it and then set a region for the new block that it is creating and you will be able to make addition just right from the block. Ok ok i know that this was extremely easy for anybody to make it. But now let's take a look how can we do exactly the same thing but without a page refresh. So let's ajaxify it as nrussell showed us in his previous code parts. Let's put them all together and create our shiny new ajaxadd module that will take us one step forward...

ajaxadd.info
------------


; $Id$
name = "ajaxadd"
description = "Makes an ajax addition with two numbers in a block. It does exactly the same as simpleadd module but without a page refresh."
core = 6.x

ajaxadd.module
---------------


// $Id: $

/**
 * Implementation of hook_menu
 *
 */

function ajaxadd_menu () {
  $items = array ();

  $items['ajaxaddresult'] = array (
	'title' => t('Ajax Addition Result'),
    'page callback' => 'ajaxadd_result',
    'access arguments' => array('access content'),
    'type' => MENU_CALLBACK,  
  );
  
  return $items;
}


/** 
 * Implementation of hook_block() 
 */ 
function ajaxadd_block($op='list', $delta=0, $edit=array()) { 
  switch ($op) { 
    case 'list': 
      $blocks[0]['info'] = t('Ajax Addition'); 
      return $blocks; 
    case 'view': 
      switch ($delta) {
        case 0:
          $blocks['subject'] = t('Ajax Addition'); 
		  drupal_add_js(drupal_get_path('module', 'ajaxadd') .'/form.js');
		  $output = '';
		  $output .= drupal_get_form('ajaxadd_form');
	      if( $_POST['ajaxadd_num1'] && $_POST['ajaxadd_num2'] && $_POST['ajaxadd_ssum'] ) {
		    $ajaxadd_num1 = $_POST['ajaxadd_num1'];  
		    $ajaxadd_num2 = $_POST['ajaxadd_num2'];  
		    $ajaxadd_ssum = $_POST['ajaxadd_ssum'];
		
		    $output .= 'Result: ' . $ajaxadd_num1 . ' + ' . $ajaxadd_num2 . ' = ' . $ajaxadd_ssum;
		    unset( $_POST['ajaxadd_num1'] );
		    unset( $_POST['ajaxadd_num2'] );
		    unset( $_POST['ajaxadd_ssum'] );
		    $blocks['content'] = $output;
	      }
	      else{
		    $blocks['content'] = drupal_get_form('ajaxadd_form');
	      }
		  //ajaxadd_result div is going to take and display the ajaxified result
		  $blocks['content'] .= '<div id="ajaxadd_result"></div>';
       	  return $blocks; 
      }
  } 
} 


/**
* Ajax callback function
*/
function ajaxadd_result() {
  $output = '';
  $ajaxadd_num1 = $_POST['ajaxadd_num1'];
  $ajaxadd_num2 = $_POST['ajaxadd_num2'];
  $ajaxadd_ssum = $ajaxadd_num1 + $ajaxadd_num2;
  
  if ( $ajaxadd_num1 && $ajaxadd_num2 && $ajaxadd_ssum ) {
    $output .= 'Result: ' . $ajaxadd_num1 . ' + ' . $ajaxadd_num2 . ' = ' . $ajaxadd_ssum;
  }
  
  print $output;
  exit;
}

/**
 * Creating the actual form itself happens here
 *
 */
function ajaxadd_form ($form_state) {

    $form = array();
  
    $form['ajaxadd_num1'] = array (
      '#type' => 'textfield',
      '#title' => t('Please enter num1'),
      '#size' => 10, 
      '#required' => TRUE,
    );
  
    $form['ajaxadd_num2'] = array (
      '#type' => 'textfield',
      '#title' => t('Please enter num2'),
      '#size' => 10,
      '#required' => TRUE,
    );
  
    $form['submit'] = array (
      '#type' => 'submit',
      '#value' => t('Ajax Addition'),  
    );
	
    return $form;
}


/**
 * Validation function, only users who input both numbers are able to submit the form
 *
 */
function ajaxadd_form_validate ($form_id, &$form_state) {
  $ajaxadd_num1 = $form_state['values']['ajaxadd_num1'];  
  $ajaxadd_num2 = $form_state['values']['ajaxadd_num2'];  

  if ( !$ajaxadd_num1 || !$ajaxadd_num2 ) {
    form_set_error('numbers', t('You must input both numbers.'));
  }
}

/**
 * form_submit function, once the form passes the validation (above) this runs
 *
 */
function ajaxadd_form_submit ($form_id, &$form_state) {
  $ajaxadd_num1 = $form_state['values']['ajaxadd_num1'];
  $ajaxadd_num2 = $form_state['values']['ajaxadd_num2'];
  $_POST['ajaxadd_num1'] = $ajaxadd_num1;
  $_POST['ajaxadd_num2'] = $ajaxadd_num2;
  $ajaxadd_ssum = $ajaxadd_num1 + $ajaxadd_num2;
  $_POST['ajaxadd_ssum'] = $ajaxadd_ssum;
}

And finally we need one more file (form.js) which will do all the ajax job and will not allow the drupal to make a page refresh. Let's ajax:

form.js
-------


$(document).ready(function(){
		
  $('form#ajaxadd-form-1').submit(function() {
    var ajaxadd_num1 = $('input#edit-ajaxadd-num1-1').val();
    var ajaxadd_num2 = $('input#edit-ajaxadd-num2-1').val();

    $.ajax({
      type: "POST",
      url: "/ajaxaddresult",
      data: "ajaxadd_num1=" + ajaxadd_num1 + "&ajaxadd_num2=" + ajaxadd_num2,
	  error: function(request, settings){
	    $('#ajaxadd_result').html("Error");
	  },
      success: function(msg){
	    $('#ajaxadd_result').html(msg);
      }
    });
    return false;
  });
});

As you can see above i didn't do something more than nrussell said at his comments but i just put all the pieces together to help someone who is going to be in my position as i was a few days ago. I tried really hard to put all these things together and i think that drupal documentation need an example like that and an even more advanced if it is possible to make everybody understand how easily can be done some things.

The code that i posted here can be downloaded from my official site at petrellis and anybody who wants to see my code live working can check it out in my experimental site http://www.drupal6.gr

I finally want to thank again nrussell and manolism for their guidance over my questions!!!! Thanks guys and keep developing...!

Emmanouil Petrellis

ramana_m’s picture

It doesn't work for me. I installed ajax module and ajaxadd but still my site is refreshing the page and clearing the input values when I submit a form :(

Thanks,
Ramana