Hello, I am trying to build a simple contact form using the form api but I haven't had much success with db_insert. I don't often post question here so I will start by copying my code in:

/*
 * Implements hook_theme
 */
function contact_theme() {
	return array(
	'contact_nameform' => array(
		'render element' => 'form',
		'template' => 'contact_nameform',
		),
	);
}

/*
 * Assign the elements of the form to variables
 */
function template_preprocess_contact_nameform(&$variables) {
	
	$variables['contact_nameform'] = array();
	$hidden = array();
	//Provides variables named after form keys
	foreach (element_children($variables['form']) as $key) {
		$type = $variables['form'][$key]['#type'];
		if ($type == 'hidden' || $type == 'token') {
			$hidden[] = drupal_render($variables['form'][$key]);
		}
		else {
			$variables['contact_nameform'][$key] = drupal_render($variables['form'][$key]);
		}
	}
	// Hidden form elements have no value to the theme
	$variables['contact_nameform']['hidden'] = implode($hidden);
	// Collect all form elements
	$variables['contact_nameform_form'] = implode($variables['contact_nameform']);
}

/*
 * Implements hook_menu()
 */

function contact_menu() {
	$items['contact'] = array(
	'title' => 'View the sample form',
	'page callback' => 'drupal_get_form',
	'page arguments' => array('contact_nameform'),
	'access callback' => TRUE,
	'type' => MENU_NORMAL_ITEM
	);
	return $items;
}
/*
 * Define the form fields
 */
function contact_nameform() {
	$form['name'] = array(
	'#title' => t('Your Name'),
	'#type' => 'textfield',
	'#description' => t('Please enter your name.')
	);
	$form['email'] = array(
	'#title' => t('Your Email'),
	'#type' => 'textfield',
	'#description' => t('Please enter your email.')
	);
	$form['comments'] = array(
	'#title' => t('Comments'),
	'#type' => 'textarea',
	'#description' => t('Type you comment'),
	);
	$form['box'] = array(
	'#type' => 'markup',
	'#prefix' => '<div id="box">',
	'#suffix' => '</div>',
	);
	$form['submit'] = array(
	'#type' => 'submit',
	'#value' => t('Submit'),
	'#executes_submit_callback' => false,
	'#ajax' => array(
		'callback' => 'contact_nameform_submit',
	  'method' => 'replace',
		'wrapper' => 'box'
	),
);
	return $form;
}

function contact_nameform_submit($form, &$form_state) {
  // In most cases, it is recomended that you put this logic in form generation
  // rather than the callback. Submit driven forms are an exception, because
  // you may not want to return the form at all.
  $element = $form['box'];
  if ($form_state['values']['name'] == '') {
  	$element['#markup'] = t('Oops!');
  } 
  elseif ($form_state['values']['email'] == '') {
  	$element['#markup'] = t('Oops!');
  } else {
   $element['#markup'] = t('Arigato');
  }
  return $element;
}
function contact_nameform_validate($form, &$form_state) {
  if ($form_state['values']['name'] == '') {
    form_set_error('name', t('Name field is required'));
  }
  if ($form_state['values']['email'] == '') {
    form_set_error('email', t('eMail field is required'));
  }
}

function contact_nameform_submit_values($form_id, &$form_state) {		
	$name = $form_state['values']['name'];
	$email = $form_state['values']['email'];
	$comments = $form_state['values']['comments'];

/*
 *  MYSQL DB Insertion
 */
$insert = db_insert('custom_contact')
	->fields(array(
		'name' => $name,
		'email' => $email,
		'comments' => $comments,
		'created' => REQUEST_TIME,
))
->execute();

This submits properly with out ajax so I know it works correctly. I must be missing something that the ajax call back is requesting???

I thank anyone who helps me...this has been plaguing me for 2 days now.

-Joseph

Comments

Anonymous’s picture

At first glance I'd say it's because you're using '#executes_submit_callback'. From the FAPI documentation:

#executes_submit_callback
Used by: button, image_button, submit
Description: Indicates whether or not button should submit the form.
Values: TRUE or FALSE

To my mind that would mean that your submit button should not submit the form at all, which is what it's doing!

If you're using that flag to stop the form submitting via non-ajax then you shouldn't be, jquery forms will take of preventing the default onclick event of your submit button from being invoked.

arkjoseph’s picture

Thanks _isos. I have removed it.

Okay I found some errors. I don't think I should be calling contact_nameform_submit prior to the validate function. I also don't need conditional within the submit function. That's why I have a separate validate function!

	<?php

/**
 * FORM API
 */

/*
 * Implements hook_theme
 */
function contact_theme() {
	return array(
	'contact_nameform' => array(
		'render element' => 'form',
		'template' => 'contact_nameform',
		),
	);
}

/*
 * Assign the elements of the form to variables
 */
function template_preprocess_contact_nameform(&$variables) {
	
	$variables['contact_nameform'] = array();
	$hidden = array();
	//Provides variables named after form keys
	foreach (element_children($variables['form']) as $key) {
		$type = $variables['form'][$key]['#type'];
		if ($type == 'hidden' || $type == 'token') {
			$hidden[] = drupal_render($variables['form'][$key]);
		}
		else {
			$variables['contact_nameform'][$key] = drupal_render($variables['form'][$key]);
		}
	}
	// Hidden form elements have no value to the theme
	$variables['contact_nameform']['hidden'] = implode($hidden);
	// Collect all form elements
	$variables['contact_nameform_form'] = implode($variables['contact_nameform']);
}

/*
 * Implements hook_menu()
 */

function contact_menu() {
	$items['contact'] = array(
	'title' => 'View the sample form',
	'page callback' => 'drupal_get_form',
	'page arguments' => array('contact_nameform'),
	'access callback' => TRUE,
	'type' => MENU_NORMAL_ITEM
	);
	return $items;
}
/*
 * Define the form fields
 */
function contact_nameform() {
	$form['name'] = array(
	'#title' => t('Your Name'),
	'#type' => 'textfield',
	'#description' => t('Please enter your name.'),
	'#required' => TRUE
	);
	$form['email'] = array(
	'#title' => t('Your Email'),
	'#type' => 'textfield',
	'#description' => t('Please enter your email.'),
	'#required' => TRUE
	);
	$form['comments'] = array(
	'#title' => t('Comments'),
	'#type' => 'textarea',
	'#description' => t('Type you comment')
	);
	$form['box'] = array(
	'#type' => 'markup',
	'#prefix' => '<div id="box">',
	'#suffix' => '</div>',
	);
//	$form['submit'] = array(
//	'#type' => 'submit',
//	'#value' => t('send'),
//	);
	$form['submit'] = array(
	'#type' => 'submit',
	'#ajax' => array(
		'callback' => 'contact_nameform_submit',
	  'method' => 'replace',
		'wrapper' => 'box'
),
	'#value' => t('Submit'),
);
	return $form;
}

function contact_nameform_validate($form, &$form_state) {
  if ($form_state['values']['name'] == '') {
    form_set_error('name', t('Name field is required'));
  }
  if ($form_state['values']['email'] == '') {
    form_set_error('email', t('Email field is required'));
  }
  
}

function contact_nameform_submit($form, &$form_state) {
  // In most cases, it is recomended that you put this logic in form generation
  // rather than the callback. Submit driven forms are an exception, because
  // you may not want to return the form at all.
  $element = $form['box'];
  $element['#markup'] = "Clicked submit ({$form_state['values']['op']}): " . date('c');
  return $element;
	
}

function contact_nameform_submit_values($form_id, &$form_state) {		
	$name = 		$form_state['values']['name'];
	$email = 		$form_state['values']['email'];
	$comments = $form_state['values']['comments'];

/*
 *  MYSQL DB Insertion
 */
$form_state = db_insert('custom_contact')
		->fields(array(
			'name' => $name,
			'email' => $email,
			'comments' => $comments,
			'created' => REQUEST_TIME,
	));
foreach ($values as $value) {
			$insert->values($value);
		}
$form_state->execute();
}
?>

_isos, your correction did not do the trick...can someone please assist me?

thank you

Anonymous’s picture

Your function contact_nameform_submit_values is never called, are you missing a call in your form's submit handler maybe?

arkjoseph’s picture

_isos, isn't that what the following is?

function contact_nameform_submit_values($form_id, &$form_state) {       
    $name =         $form_state['values']['name'];
    $email =         $form_state['values']['email'];
    $comments = $form_state['values']['comments'];

/*
*  MYSQL DB Insertion
*/
$form_state = db_insert('custom_contact')
        ->fields(array(
            'name' => $name,
......
Anonymous’s picture

That's the function declaration, but where is that function actually called from? I can't see it in the code you've provided, apologies if I've missed it though

arkjoseph’s picture

I will look into it and post back. thank you for the tip

arkjoseph’s picture

Okay, no success as of yet...

<?php
/*
 * Implements hook_menu()
 */
function contact_menu() {
	$items['contact'] = array(
		'title' => 'View the sample form',
		'page callback' => 'drupal_get_form',
		'page arguments' => array('contact_nameform'),
		'access callback' => TRUE,
		'type' => MENU_NORMAL_ITEM
	);
	return $items;
}
/*
 * Implements hook_theme
 */
function contact_theme() {
	return array(
	'contact_nameform' => array(
		'render element' => 'form',
		'template' => 'contact_nameform',
		),
	);
}

/*
 * Assign the elements of the form to variables
 */
function template_preprocess_contact_nameform(&$variables) {
	$variables['contact_nameform'] = array();
	$hidden = array();
	//Provides variables named after form keys
	foreach (element_children($variables['form']) as $key) {
		$type = $variables['form'][$key]['#type'];
		if ($type == 'hidden' || $type == 'token') {
			$hidden[] = drupal_render($variables['form'][$key]);
		}
		else {
			$variables['contact_nameform'][$key] = drupal_render($variables['form'][$key]);
		}
	}
	// Hidden form elements have no value to the theme
	$variables['contact_nameform']['hidden'] = implode($hidden);
	// Collect all form elements
	$variables['contact_nameform_form'] = implode($variables['contact_nameform']);
}


/*
 * Define the form fields
 */
function contact_nameform($form, &$form_state) {
// NEW LINE ADDED.  IS THIS PART CORRECT?
	$form['#id'] = 'contact';
	$form['#contact'] = $contact;
	$form_state['contact'] = $contact;
// Fields
	$form['name'] = array(
	'#title' => t('Your Name'),
	'#type' => 'textfield',
	'#description' => t('Please enter your name.'),
	'#required' => TRUE
	);
	$form['email'] = array(
	'#title' => t('Your Email'),
	'#type' => 'textfield',
	'#description' => t('Please enter your email.'),
	'#required' => TRUE
	);
	$form['comments'] = array(
	'#title' => t('Comments'),
	'#type' => 'textarea',
	'#description' => t('Type you comment')
	);
	$form['box'] = array(
	'#type' => 'markup',
	'#prefix' => '<div id="box">',
	'#suffix' => '</div>',
	);
	$form['submit'] = array(
	'#type' => 'submit',
	'#ajax' => array(
		'callback' => 'contact_nameform_submit',
	  'method' => 'replace',
		'wrapper' => 'box'
),
	'#value' => t('test form'),
);
	return $form;
}

function contact_nameform_validate($form, &$form_state) {
  if ($form_state['values']['name'] == '') {
    form_set_error('name', t('Name field is required'));
  }
  if ($form_state['values']['email'] == '') {
    form_set_error('email', t('Email field is required'));
  }
// NEW LINE ADDED
  $form_state['contact']['info'] = $info_data;
}
function contact_nameform_submit($form_id, &$form_state) {
  // In most cases, it is recomended that you put this logic in form generation
  // rather than the callback. Submit driven forms are an exception, because
  // you may not want to return the form at all.
  $element = $form['box'];
  $element['#markup'] = "Clicked submit ({$form_state['values']['op']}): " . date('c');
  return $element;

//function contact_nameform_submit_values($form_id, &$form_state) {		
	
// NEW LINE ADDED	
  $info_data = $form_state['contact']['info'];
	
	$name = $form_state['values']['name'];
	$email = $form_state['values']['email'];
	$comments = $form_state['values']['comments'];

	drupal_set_message(t('Thank you %name. Please check your inbox at %email for confirmation.',
	array('%name' => $name, '%email' => $email)));
	
/*
 *  MYSQL DB Insertion
 */
db_insert('custom_contact')
		->fields(array(
			'name' => $name,
			'email' => $email,
			'comments' => $comments,
			'created' => REQUEST_TIME,
	))
->execute();
}
?>

Can you test my code please, I am just going bonkers over this simple task. Nothing is getting passed to the database! Is there a firebug plugin available that I could possibly use?

Let me know if the problem is discovered. I took your advise and added the lines under // NEW LINE ADDED . Let me know if im doing things correct.

-Joe

Anonymous’s picture

You're nearly there, in your contact_name_submit function you've got 'return $element;' before you commit the record to the database. Move this code:

// In most cases, it is recomended that you put this logic in form generation
  // rather than the callback. Submit driven forms are an exception, because
  // you may not want to return the form at all.
  $element = $form['box'];
  $element['#markup'] = "Clicked submit ({$form_state['values']['op']}): " . date('c');
  return $element;

to the bottom of contact_name_submit, after you've written the record to the database. It should work fine then

arkjoseph’s picture

It works! Updated code...

<?php
function contact_nameform_validate($form, &$form_state) {
  if ($form_state['values']['name'] == '') {
    form_set_error('name', t('Name field is required'));
  }
  if ($form_state['values']['email'] == '') {
    form_set_error('email', t('Email field is required'));
  }
}
function contact_nameform_submit($form, &$form_state) { 
  $element = $form['box'];
  $element['#markup'] = "Clicked submit ({$form_state['values']['op']}): " . date('c');
	// POST Info
	$name = $form_state['values']['name'];
	$email = $form_state['values']['email'];
	$comments = $form_state['values']['comments'];

	drupal_set_message(t('Thank you %name. Please check your inbox at %email for confirmation.',
	array('%name' => $name, '%email' => $email)));
	
/*
 *  MYSQL DB Insertion
 */
db_insert('custom_contact')
		->fields(array(
			'name' => $name,
			'email' => $email,
			'comments' => $comments,
			'created' => REQUEST_TIME,
	))
->execute();
  return $element;
}
?>

now I seem to have a strange issue of the date getting input twice when i only clicked submit once. Could it be due to my validation?

arkjoseph’s picture

sorry, not the date, the data...

Anonymous’s picture

I'm not 100% on this but I think the submit handler would automatically be called for an ajax callback anyway, so if your ajax callback is also the submit function it'll get run twice.

If you separate the code out it should work

function contact_nameform_submit($form, &$form_state) {
  /*
 *  MYSQL DB Insertion
 */
db_insert('custom_contact')
        ->fields(array(
            'name' => $name,
            'email' => $email,
            'comments' => $comments,
            'created' => REQUEST_TIME,
    ))
->execute();
}

function contact_nameform_ajax_callback(&$form, &$form_state) {
  $element = $form['box'];
  $element['#markup'] = "Clicked submit ({$form_state['values']['op']}): " . date('c');
    // POST Info
    $name = $form_state['values']['name'];
    $email = $form_state['values']['email'];
    $comments = $form_state['values']['comments'];

    drupal_set_message(t('Thank you %name. Please check your inbox at %email for confirmation.',
    array('%name' => $name, '%email' => $email)));

  return $element;
}

Then change you ajax callback for $form['submit'] in contact_nameform() to 'contact_nameform_ajax_callback' and you should be good to go!

Anonymous’s picture

I'm not 100% on this but I think the submit handler would automatically be called for an ajax callback anyway, so if your ajax callback is also the submit function it'll get run twice.

If you separate the code out it should work

function contact_nameform_submit($form, &$form_state) {
$name = $form_state['values']['name'];
    $email = $form_state['values']['email'];
    $comments = $form_state['values']['comments'];
  /*
 *  MYSQL DB Insertion
 */
db_insert('custom_contact')
        ->fields(array(
            'name' => $name,
            'email' => $email,
            'comments' => $comments,
            'created' => REQUEST_TIME,
    ))
->execute();

drupal_set_message(t('Thank you %name. Please check your inbox at %email for confirmation.',
    array('%name' => $name, '%email' => $email)));
}

function contact_nameform_ajax_callback(&$form, &$form_state) {
  $element = $form['box'];
  $element['#markup'] = "Clicked submit ({$form_state['values']['op']}): " . date('c');
  
  return $element;
}

Then change you ajax callback for $form['submit'] in contact_nameform() to 'contact_nameform_ajax_callback' and you should be good to go!

EDIT: I've updated it to be a bit cleaner

arkjoseph’s picture

Works like a charm. I am learning form API on my own until now.

thank you!