欢迎各位兄弟 发布技术文章

这里的技术是共享的

You are here

drupal form_set_error multiple fields form_set_error Question

Setting errors on multiple elements

hi,

i have very frustrating question. i am trying to make a form module which have a three fields together like sortcode have three different fields. now i have to make a validation in which if one of the three ll be wrong all three fields will be highlighted. but problem is this i want to show only one error message.

only solution in the below but it ll create two empty list items. which is not good for usibility.

form_set_error('element1',$message');
form_set_error('element2', ' ');
form_set_error('element3', ' ');

is there anyother solution is there. so we can highlight three fields and show only one message.

thanks

Comments

vasi1186’s picture

Hi,

here is a possible solution for you. The idea is to group the form items within a parent. See below a small example:

function custom_test_form(){
	$form = array();
	$form['wrapper']['element1'] = array(
		'#type' => 'textfield',
		'#title' => t('dummy test'),
	);
	$form['wrapper']['element2'] = array(
		'#type' => 'textfield',
		'#title' => t('dummy test3'),
	);
	$form['wrapper']['element3'] = array(
		'#type' => 'textfield',
		'#title' => t('dummy test3'),
	);
	$form['wrapper']['#tree'] = TRUE;
	$form['submit'] = array(
		'#type' => 'submit',
		'#value' => t('submit')
	);
	return $form;
}

The important line is

  $form['wrapper']['#tree'] = TRUE;

In the validation of the form, you can do something like:

if (validation_fails){
  form_set_error('wrapper', t('Some error message!'));
}

So, instead of putting 3 errors, you just put one single error on the parent. Also, please remember that if you specify the #tree attribute in the form, you must also consider the values in the $form_state['values'] as a tree. Something like this:

function custom_test_form_submit($form, &$form_state){
	$element1_value = $form_state['values']['wrapper']['element1'];
        $element2_value = $form_state['values']['wrapper']['element2'];
       //.....etc
}

Hope this helps,

Vasi.

naseem_sarwar’s picture

hi,

your code was quite helpful. i just need a final step from you. i have implemented that code but it is not working. only thing is this i have 15 fields and only 3 of them should be together. i made like your example. i got the values in validation but when i put the error it give the one message but it did not highlight the fields.

any idea? why it is not doin it.
$form['name']['AccountName'] = array(
'#type' => 'textfield',
'#title' => t('Account Name* '),

);
$form['payment']['element1'] = array(
'#type' => 'textfield',
'#title' => t('element1* '),
//'#required' => TRUE,
'#size' => 2,
'#maxlength' => 2,

);
$form['payment']['element2'] = array(
'#type' => 'textfield',
'#size' => 2,
'#maxlength' => 2,
);
$form['payment']['element3'] = array(
'#type' => 'textfield',
'#size' => 2,
'#maxlength' => 2,

);
$form['payment']['#tree'] = TRUE;

then i have more fields with [name] too.

now on validation
if(validation)
{
form_set_error('payment', t('Please enter '));
}

it show one message on top. but if does not highlight any of the fields.

vasi1186’s picture

Hi,

can you try to put all the fields inside a common parent, even if they do not logically belong to that parent. For example:

$form['parent_name']['name_first']['AccountName'] = ...
$form['parent_name']['payment']['element1'] = ...
$form['parent_name']['payment']['element2'] = ...
$form['parent_name']['payment']['element3'] = ...
$form['parent_name']['name_second']['otherField1'] = ...
$form['parent_name']['name_second']['otherField2'] = ...

and in the validation:

form_set_error('parent_name', t('Please enter'));

Can you try like that?

Vasi.

naseem_sarwar’s picture

hi,

i again try your example. but only one problem i got. in above code i want to show error only on payment elements. how can i do that?
i tried this but it didnt work.

form_set_error('parent_name][payment', t('Please enter'));

am i doing right? please advise!

vasi1186’s picture

Hi,

for that, you should only need this:

$form['AccountName'] = ...
$form['payment']['element1'] = ...
$form['payment']['element2'] = ...
$form['payment']['element3'] = ...
$form['otherField1'] = ...
$form['otherField2'] = ...
$form['payment']['#tree'] = TRUE;

and then, in validation,

form_set_error('payment', t('Please enter'));

来自  https://www.drupal.org/node/155695




form_set_error Question

Does anyone know if it’s possible to have form_set_error() apply to multiple fields?

if((condition1) || (condition2)) {
  form_set_error(‘conditionfield1’,’conditionfield2’,t(‘Wow, what an error’));
}

Or maybe something like…


if((condition1) || (condition2)) {
  form_set_error(‘conditionfield1’, t(‘Wow, what an error’));
  form_set_error(’conditionfield2’, t(‘Wow, what an error’));
}

Does anything like this make sense?
Thanks

Comments

NancyDru’s picture

Interesting question. I don't see what you couldn't at least do the second method. I'll be interested in what other answers come up.

Nancy W.
Drupal Cookbook (for New Drupallers)
Adding Hidden Design or How To notes in your database

naseem_sarwar’s picture

not tested, but it should work...

if (condition) {
  form_set_error(NULL, t(‘Wow, what an error’));
  form_set_error('conditionfield1');
  form_set_error('conditionfield2');
}

José San Martin
http://www.verinco.com/
http://www.gare7.org/
http://www.studying-linguistics.com/

naseem_sarwar’s picture

That did work, thanks!

There might have been some weird issues with resolution after the error message, but the initial error display worked fine. I say 'might' because we ended up changing our logic, yielding that condition useless, so I did not test it further. But thanks for your help!

johnhanley’s picture

I came across this question today.

I'm not sure what version you're referring to, but under Drupal 5.x your (albeit untested) example doesn't work. If you look at the code for form_set_error it's easy to see why. Setting the first name parameter to NULL will cause isset() to return false. Also, not defining the second message parameter will prevent drupal_set_message() from firing.

According to the documentation, form_set_error is suppose to allow setting errors for multiple fields by grouping them together as child elements, but I wasn't able to get this to work either.

naseem_sarwar’s picture

Yeah, the above example is not supposed to work.

Could you please open a feature request?

johnhanley’s picture

I'd be curious to know if anyone has successfully used form_set_error() according to the documentation.

NancyDru’s picture

If you mean in the standard manner (one error, one field, one message), yes - there are many examples throughout core as well.

Nancy W.
Drupal Cookbook (for New Drupallers)
Adding Hidden Design or How To notes in your database

naseem_sarwar’s picture

form_set_error is suppose to allow setting errors for multiple fields by grouping them together as child elements, but I wasn't able to get this to work

It works. Perhaps you didn't use #tree => TRUE on the parent element?

(There's one small error in the doc: Nowadays elements aren't named edit[foo][bar] but simply foo[bar]. But don't mention this in your issue; it isn't relevant.)

johnhanley’s picture

That is: one error, multiple fields, one message.

I have the #tree attribute set to TRUE.

I also noted the syntax error.

Still no success. I've moved on to other more important project tasks, but will revisit this later.

naseem_sarwar’s picture

Well, after lot's of testing, I find a solution, while not very nice, it just works.

The above code didn't worked for me (Drupal 6 right now) as when adding NULL to the error won't print and fields won't get marked if an error message is not passed (neither with '' as message), so I fixed it passing a blank space as message.

This worked for me:

<?php
if (condition) {
  form_set_error('conditionfield1', t(‘Wow, what an error’));
  form_set_error('conditionfield2', ' ');
}
?>

Now I have the two fields marked as error and just a blank list entry on the errors list... can live with it.. :)

Hopes this helps anybody.

johnhanley’s picture

botum, thanks for sharing your findings.

I discovered another technique for displaying multiple error messages is to use form_set_error for the first message and drupal_set_message (with the second parameter set to 'error') for any additional messages. This won't solve the problem you're talking about though.

naseem_sarwar’s picture

up. I've this problem, too. I'd like to get a single error message, while highlighting two or more fields. Is it possible to do that?

I tried also with form_set_error( array('FirstField', 'SecondField'), t('FF has to be > than SF!') ) but it doesn't work...

No solution for this (common?) question?

johnhanley’s picture

So nearly 1 1/2 years later since the original post of this thread the inability to display one error message for multiple fields still persists.

I need the ability to highlight (i.e. red outline style by default) multiple fields while only displaying one error message. For example:

<?php
  form_set_error('address1', t(‘Please complete all the required address fields.));
  form_set_error('city');
  form_set_error('state');
  form_set_error('postal');
}
?>

Currently in the above example only the 'address1' field is highlighted.

Interesting excluding the second message string argument from form_set_error() still allows the fieldname to be added to the static form array, but the field highlighting is ignored.

<?php
function form_set_error($name = NULL, $message = '') {
  static $form = array();
  if (isset($name) && !isset($form[$name])) {
    $form[$name] = $message;
    if ($message) {
      drupal_set_message($message, 'error');
    }
  }
  return $form;
}
?>

Yeah, I can define the second argument as a space like so

<?php
  form_set_error('postal', ' ');
}
?>

but this is a lame workaround and adds extra space to the error message div.

-------------------------------------------------------

"If you don't read the newspaper you are uninformed;
if you do read the newspaper you are misinformed."
-- Mark Twain

naseem_sarwar’s picture

I'm pretty sure the above solution only works if the password fields are the only fields being passed into password_confirm_validate().

If you don't want to set the two, or more, comparative form elements under a common parent (looking at the code, this is what seems to make form_error() really work), I suggest setting the first element with form_set_error() as explained a bit further above, and then setting a flag value to rebuild the attributes of the other form elements.

Looking at the source code, I found that the error highlighting around form fields is turned on by adding the class 'error' to the form element.

So starting within your hook_validate function with form elements 'email' and 'confirm_email':

<?php
function myform_form_validate ($form, &$form_state) {
	$error = FALSE;
	// ...any other validation checks, making sure that $error is set to true if a validation check fails

	// If there are any previous validation errors, error message will exist -> set $error = TRUE
	$errors = form_get_errors();
	if (!empty($errors)) {
		$error = TRUE;
	}

	if ($form_state['values']['email'] != $form_state['values']['confirm_email']) {
		form_set_error('email', 'Email verification failed, please try again.');
		$form_state['rebuild'] = TRUE;
		$form_state['whitepaper']['confirm_email_error'] = TRUE;
	} else {
		if ($error) {
			$form_state['rebuild'] = TRUE;
		}
		$form_state['whitepaper']['confirm_email_error'] = FALSE;
	}
}
?>

The key above being setting $form_state['rebuild'] = TRUE, after setting your flag value to be 1. Also, we need another sentinel value $error to mark if there are any other errors in the validation process. Because $form_state['rebuild'] ignores any $form_state['redirect'] value, the $error needs to be turned on. That way if there are any previous failures in validation the form will rebuild itself, and re-present itself to the user. Otherwise, the form will proceed as expected.

Then in your hook_form:

<?php

function myform_form($form_state) {
	$form['name'] = array(
		'#type' => 'textfield',
		'#title' => t('Full Name'),
		'#required' => TRUE,
		'#default_value' => (isset($form_state['values']['name'])) ? $form_state['values']['name'] : '',
	);

	// ...additional form fields

	$form['email'] = array(
		'#type' => 'textfield',
		'#title' => t('Email Address'),
		'#required' => TRUE,
	);
	
	if (isset($form_state['mymodule']['confirm_email_error']) && $form_state['mymodule']['confirm_email_error'] === TRUE) {
		$attributes = array('class' => 'error');
	} else {
		$attributes = array();
	}
	
	$form['confirm_email'] = array(
		'#type' => 'textfield',
		'#title' => t('Confirm Email'),
		'#required' => TRUE,
		'#attributes' => $attributes,
	);
	
	// ... any other fields
	
	return $form;
}
?>

Setting $form_state['rebuild'] = TRUE will allow you to reset the attributes after validation. For additional form fields, just set '#atttributes' => $attributes.

I included the form element 'name' to illustrate that any values that you want repopulated when the form rebuilds, you have to use the '#default_value' property for the form element, otherwise the value is not populated.

Not all pretty, but does work.

naseem_sarwar’s picture

Has this changed? I'm doing something similar to this, but I can't seem to get past form.inc line 141 if I set an error - it doesn't rebuild the form, it just re-renders it, which doesn't seem to give my form function a chance to do anything differently...

dnotes.net

naseem_sarwar’s picture

Sometimes trying to do things 'The Drupal Way' seems just waaay too much work, assuming it's even possible. I just use something like this. Crude. Works.

form_set_error('element_name', t('Error'));
array_pop($_SESSION['messages']['error']);

If your repeated errors are not sequential, you'll need to expand on that a bit...

naseem_sarwar’s picture

John,

I agree with the waaay too much work sometimes. Your solution worked fine thanks, just popped every message as I created them and then did the below to get an actual message up.

  if (form_get_errors()) {
    drupal_set_message($msg, 'error');
  }

Anthony.

colemanw’s picture

Popping all but one makes more sense to me.

asiby’s picture

Simply filter the array to remove duplicates.

$_SESSION['messages']['error'] = array_filter($_SESSION['messages']['error']);

Live long ... and prosper!

naseem_sarwar’s picture

I think you mean

$_SESSION['messages']['error'] = array_unique($_SESSION['messages']['error']);

which would remove all duplicate error messages. I recently used this to solve the problem described in this thread.

naseem_sarwar’s picture

i am strggling to do that. can anyone give me example for that. i am really struggling to get this done.

jduhls’s picture

Thanks for this one! Elegant solution!

asiby’s picture

Thank keyfarmer. That's wha i meant.

Live long ... and prosper!

naseem_sarwar’s picture

set #parents => array('foo'), on each element that is to be highlighted together (in my case i require either a telephone number or an email address for my form)

in your validation/submission function put form_set_error($name = 'foo', $message = 'how much do you all love me?');

naseem_sarwar’s picture

don't forget to apply $form['#tree'] = TRUE

naseem_sarwar’s picture

The array_pop method would remove other error messages, so that can't be assumed "safe".

The message above about setting #parent would certainly work, but you'd set errors on every child, even those that contain data and are already correct.

I think the best thing to do is run <?php $_SESSION['messages']['error'] = array_unique($_SESSION['messages']['error']); ?> at the end of your _form_validate() function after setting errors on everything that's an error.

Edit: Well, you'd really want to make sure the ['error'] array exists before setting it, otherwise you'll print errors even when there are none!

<?php
// Remove duplicate messages.
if (isset($_SESSION['messages']['error'])) {
  $_SESSION['messages']['error'] = array_unique($_SESSION['messages']['error']);
}
?>
Leksat’s picture

There is a way to mark form element as error suppressing error message.

form_error($form['element1'], t('Error'));
form_error($form['element2'], 'will be removed');
array_pop($_SESSION['messages']['error']); // Right after form_error() call.
naseem_sarwar’s picture

This worked for me with clean HTML output in the error box:

<?php 
form_set_error('email', t('Sorry, the passwords do not match. Please try again.'));
form_set_error('confirmemail', NULL);
?>

 

Sorry - spoke too soon, it is only highlighting one of the fields!

naseem_sarwar’s picture

<?php
form_set_error('username', 'Text is Irrelevant');	// Set Error to the UserName Field 
$messages = drupal_get_messages('error', true);			// Get Rid of the First Error Message
form_set_error('password', t('Wrong UserName or Password'));	// Set Error to the Password Field (The visible message)
?>

That is tested and Works

johnhanley’s picture

$messages = drupal_get_messages('error', true);

This example will "get rid" (aka. clear queue) of all messages of "error" type, not just "the first error message". In many/most cases this is not desirable as you risk clearing other relevant error messages.

naseem_sarwar’s picture

The following code is showing error message only once but highlighting in red three fields:

        form_set_error('cities',t("You can select maximum of $MAX_SELECTIONS choices!"));
        form_set_error('states','');
        form_set_error('societies','');
johnhanley’s picture

It's funny how this issue still crops up from time to time. That is, highlighting multiple fields while displaying only one error message.

Indeed, setting additional fields via form_set_error() with an empty message string works in Drupal 7. It seems like back in Drupal 6 days doing so would output extra line breaks.

@rag_gupta, it's considered best practice to pass variables to the translate (T) function as an associative array of replacements versus inserting them directly into the string via PHP.



来自  https://www.drupal.org/node/155695


普通分类: