Hi all,

I'm creating my very first Drupal module (Drupal 7, btw) and I'm almost done with it. There is one last thing and that is that I need to get the values from multiple checkboxes.

My module list certain nodes and each of them gets a checkbox using a foreach $nid. All using the Form API.

Now, when the form is submitted, only one (1) value is returned - and as of now, not even the one that I check, but the last nodes ID.

Perhaps it is because each new value replaces the previous(?). Or something is wring with my code. Someone in the IRC channel told be that the forms checkbox returns an array of the values, but I'm trying to use foreach of that value, without any success.

What could be the problem?
Here is my code - shorted down.

function my_module_cmp($a, $b) {

  $a = (array) $a;

  $b = (array) $b;

  return strcmp($a['name'], $b['name']);

}

function my_module_form() {
	$url = taxonomy_get_term_by_name(arg(1));
	foreach($url as $term) {
		$tid = $term->tid;
	}
	$term = taxonomy_term_load($tid);
	$name = taxonomy_term_title($term);
	$terms = taxonomy_get_tree(3,0,1);
	usort($terms, "my_module_cmp");
	$counter = 0;
	$result = taxonomy_select_nodes($tid);
	foreach($result as $nid) {
		$form[$nid] = array (
			'#type' => 'fieldset'
		);
		// title
		$form[$nid]['title'] = array (
			'#markup' => '<div class="title"><a href="/'.$nid.'">' . $node->title . '</a></div>',
		);
		// checkbox
		$form[$nid]['company'] = array (
			'#type' => 'checkbox',
			'#title' => t('Check the nodes balbla'),
			'#title_display' => 'attribute',
			'#return_value' => $nid,
			'#default_value' => 0,
			'#prefix' => '<a class="checkbox">Skicka förfrågan till företaget >>',
			'#suffix' => '</a>',
		);
	$counter++;
	}
	return $form;
}

function my_module_form_validate($form, &$form_state) {
	// Validate that a company has been checked, at all
	$valid_company = $form_state['values']['company'];
		if (!$valid_company) {
		form_set_error('company', 'Forgot to check something');
		}
}

function my_module_form_submit($form, &$form_state) {
	$company = $form_state['values']['company'];
	drupal_set_message('<pre>'.print_r($form_state['values'], 1).'</pre>'); // Check out the values

	foreach ($company as $nid) {
		// Get the node from nid
		$node = node_load($nid);
		// Get the author of that node
		$user = user_load(array('uid' => $node->uid));
		drupal_set_message(t('DEBUG node:'.$nid.', user: '.$user->name.','.$user->mail.'')); // TEST



		// Check if the mail has been sent and show a message based on that
		if (drupal_mail('my_module', 'token', $user->mail, language_default(), $message, $from, TRUE)) {
			drupal_set_message(t('Offert been sent %name',array('%name' => $user->name)));
		}
		else {
			drupal_set_message(t('Error')); 
		}
	} 
}

Comments

Anonymous’s picture

At the moment you're checking for $form_state['values']['company'], but you have never set an element called $form['company'] in the form function, so that value won't exist. Also you're outputting $node->title, when the $node object has not been set in your code anywhere.

You can do what your trying to do with your current code but I'd suggest changing it to use the checkboxes form type instead:

In your form function:

$result = taxonomy_select_nodes($tid);
$options = array();
foreach ($result as $nid) {
  $node = node_load($nid);
  $options[$nid] = $node->title;
}

$form['company'] = array(
  '#type' => 'checkboxes',
  '#title' => 'Title',
  '#options' => $options,
  '#default_value' => array()
);

and in your submit function:

$nids = array_filter($form_state['values']['company']);

foreach ($nids as $nid) {
  // Do what you need to with the nids...
}

Hope that helps

EDIT
----

One other little thing, your form function should have the required parameters for consistency:

function my_module_form($form, &$form_state) {
  ...
}
nevets’s picture

My guess is you need to change the fieldset to

$form[$nid] = array (
'#type' => 'fieldset',
'#tree' => TRUE
);

That way the elements will in the fieldset will retain the node id in the value structure. Another approach would be to use a single set of checkboxes, something like

$options = array();
foreach($result as $nid) {
   $node = node_load($nid);
   $options[$nid] = $node->title;
}
// checkbox
$form['companies'] = array (
'#type' => 'checkboxes',
'#title' => t('Check the nodes balbla'),
'#title_display' => 'attribute',
'#options' => $options,
'#default_value' => 0,
'#prefix' => '<a class="checkbox">Skicka förfrågan till företaget >>',
'#suffix' => '</a>',
);
d.holmen@gmail.com’s picture

Thanks guys,

I'm trying out both of your tips but I cant figure it out completely. I get as far as multiple values are shown with: drupal_set_message('<pre>'.print_r($form_state['values'], 1).'</pre>');

Looks like:
[509] => Array
(
[companies] => 509
)

[508] => Array
(
[companies] => 508
)

How do I get into that value now? I cant use:
$nids = $form_state['values']['companies'];

I would have to get the id somehow or is there another way?

Anonymous’s picture

See the first reply:

$nids = array_filter($form_state['values']['companies']);

if you're using the multiple checkbox method. If you're using the #tree method then I'd suggest wrapping all your values in another wrapper in the form so you can easily walk through them in your submit function.

$form['company_wrapper'] = array('#tree' => TRUE);
...
foreach ($result as $nid) {
  $form['company_wrapper'][$nid] = array(
    '#type' => 'fieldset'
  );
  ...
}

then in your submit function you can just do this:

$nids = array_keys($form_state['values']['company_wrapper']);
d.holmen@gmail.com’s picture

Thank you,

Now I get the nids, but I get them even if I havent checked the checkboxes?

Anonymous’s picture

Yep, you need to check the 'companies' value of each array item to see if it's the nid or zero (zero means unchecked). It would be a lot easier to do it using the checkboxes rather than using #tree.

d.holmen@gmail.com’s picture

I dont know how to do that so I changed to checkboxes instead. Now an extra checkbox is added with the name $nid--2 and if check the node with that extra checkbox, the form fails and asks me to contact admin.

Anonymous’s picture

It definitely shouldn't be adding an extra checkbox if you've used the code from either of the examples above, could you post your current code? I'm sure it'll be something simple

d.holmen@gmail.com’s picture

Ok, now there isnt an extra checkbox anymore, but I can only check one box, on my dev page.

function my_module_menu() {

  $items['kategori'] = array(

    'page callback' => 'my_module_kategori',

    'access callback' => TRUE,

    'type' => MENU_CALLBACK,

  );

  return $items;

}


function my_module_cmp($a, $b) {

  $a = (array) $a;

  $b = (array) $b;

  return strcmp($a['name'], $b['name']);

}


function my_module_kategori() {

	// Show both the form and the title

	return array(

		'form' => drupal_get_form('my_module_form'),

	);

}

function my_module_form($form, &$form_state) {

	// The form

	$form['offert'] = array(

		'#title' => t('Skicka offertförfrågan till FLERA leverantörer samtidigt!'),

		'#type' => 'fieldset'

	);

	$form['offert']['question'] = array(

		'#type' => 'textarea',

		'#title' => t('Förfrågan'),

		'#default_value' =>  t('Skriv en förfrågan till dina utvalda leverantörer här....'),

		'#cols' => 50,

		'#rows' => 5,

		'#resizable' => FALSE

	);

	$form['offert']['name'] = array(

		'#type' => 'textfield',

		'#title' => t('Namn'),

		'#default_value' => t('Ditt namn....'),

		'#size' => 33,

		'#maxlength' => 64

	);

	$form['offert']['mail'] = array(

		'#type' => 'textfield',

		'#title' => t('Epost'),

		'#default_value' => t('Epost....'),

		'#size' => 14,

		'#maxlength' => 30

	);

	$form['offert']['compname'] = array(

		'#type' => 'textfield',

		'#title' => t('Företagsnamn'),

		'#default_value' => t('Företagsnamn....'),

		'#size' => 15,

		'#maxlength' => 64

	);

	$form['offert']['phone'] = array(

		'#type' => 'textfield',

		'#title' => t('Telefon'),

		'#default_value' => t('Telefon...'),

		'#size' => 14,

		'#maxlength' => 20

	);

	$form['offert']['comptype'] = array(

		'#type' => 'textfield',

		'#title' => t('Företagstyp'),

		'#default_value' => t('Typ av företag...'),

		'#size' => 15,

		'#maxlength' => 64

	);

	$form['offert']['submit'] = array(

		'#type' => 'submit',

		'#value' => t('Skicka')

	);



	// The html

	$url = taxonomy_get_term_by_name(arg(1));

	foreach($url as $term) {

		$tid = $term->tid;

	}

	$term = taxonomy_term_load($tid);

	$name = taxonomy_term_title($term);

	$terms = taxonomy_get_tree(3,0,1);

	usort($terms, "my_module_cmp");

	$counter = 0;

	$result = taxonomy_select_nodes($tid);

	$options = array();



	foreach($result as $nid) {

		$form[$nid] = array(

			'#type' => 'fieldset',

		);

		$node = node_load($nid);

		$options[$nid] = $node->title;

		$phone = db_query("SELECT field_phone_value FROM {field_data_field_phone} WHERE entity_id=$nid")->fetchField();

		$body = db_query("SELECT body_value FROM {field_data_body} WHERE entity_id=$nid")->fetchField(); 



		// company image

		$form[$nid]['logo'] = array (

			'#markup' => '<div class="logo"><a href="/branschguiden/'.$nid.'"><img src="hdfsd01372593e5e.gif"></a></div>',

		);



		// title

		$form[$nid]['title'] = array (

			'#markup' => '<div class="title"><a href="/branschguiden/'.$nid.'">' . $node->title . '</a></div>',

		);



		// body

		$form[$nid]['body'] = array (

			'#markup' => '<div class="body"><a href="/branschguiden/'.$nid.'">' . $body . '</a></div>',

		);



		// phone

		$form[$nid]['phone'] = array (

			'#markup' => '<div class="phone"><img src="/sites/hrtorget/themes/hrtorget/images/phone-icon.png">'.$phone.'</div>',

		);



		// checkbox

		$form[$nid]['companies'] = array (

			'#type' => 'checkboxes',

			'#title' => t('Check it'),

			'#options' => $options,

			'#default_value' => array(),

		);



	$counter++;

	}

	return $form;

}

function my_module_form_validate($form, &$form_state) {
	// Validate that a company has been checked, at all

	$valid_companies = $form_state['values']['companies'];

		if (!$valid_companies) {

		form_set_error('companies', 'Du har inte kryssat i något företag');

		}
}

function my_module_form_submit($form, &$form_state) {

	// Send mail to each of the checked companies with the date from the form

	$values = $form_state['values'];

	$question = $form_state['values']['question'];

	$name = $form_state['values']['name'];

	$mail = $form_state['values']['mail'];

	$compname = $form_state['values']['compname'];

	$comptype = $form_state['values']['comptype'];

	$phone = $form_state['values']['phone'];

	$to = 'Ann array of all the checked companies email';

	$from = 'test$tesfd.com';

	$subject = 'Offer';



	// Get the checkbox values from the form

//	$nids = array_keys($form_state['values']['company_wrapper']);

	$nids = array_filter($form_state['values']['companies']);





	// Print all the values from the form

	drupal_set_message('<pre>'.print_r($form_state['values'], 1).'</pre>');

//	drupal_set_message('<pre>'.print_r($form_state['values']['company_wrapper'], 1).'</pre>');

	drupal_set_message('<pre>'.print_r($form_state['values']['companies'], 1).'</pre>');

//	dpm($form_state['values']['company_wrapper']);



	$body = 'Mesage text with a all the stuff from the form';



	$message = array(

	'body' => $body,

	'subject' => $subject,

	);



	foreach ($nids as $nid) {

		// Get the node from nid

		$node = node_load($nid);

		// Get the author of that node

		$user = user_load(array('uid' => $node->uid));

		drupal_set_message(t('DEBUG nod:'.$nid.', användare: '.$user->name.','.$user->mail.'')); // DEBUG



		// Check if the mail has been sent and show a message based on that

		if (drupal_mail('my_module', 'branschguiden', $user->mail, language_default(), $message, $from, TRUE)) {

			drupal_set_message(t('Mail sent to %name',array('%name' => $user->name)));

		}

		// If no mail was sent.

		else {

			drupal_set_message(t('Error')); 

		}

	}

}


nevets’s picture

When using checkboxes the options array needs to be build first so it would have to go after the loop that builds $options and does not need/want $nid so it would look like

         } // End of loop that builds $options
        $form[['companies'] = array (

            '#type' => 'checkboxes',

            '#title' => t('Check it'),

            '#options' => $options,

            '#default_value' => array(),

        );
d.holmen@gmail.com’s picture

Wont that mean that there wont be a checkbox for each entity? They have to be together with the node.

earlyburg’s picture