I have a custom form that uses ajax submit successfully. However, form validation is not working as expected. Fields marked as required are being highlighted in red, but other fields that do not pass validation are not being marked.
function my_custom_form($form, &$form_state, $nid=NULL) {
global $user;
$form['nid'] = array(
'#type' => 'hidden',
'#value' => $nid,
);
$form['#attributes'] = array('enctype' => "multipart/form-data");
$form['video_fid'] = array(
'#title' => t('Video'),
'#type' => 'managed_file',
'#description' => t('Upload your video.'),
'#default_value' => variable_get('video_fid', ''),
'#upload_location' => 'public://video/',
'#upload_validators' => array(
'file_validate_extensions' => array('mp4'),
// Pass the maximum file size in bytes
'file_validate_size' => array(MAX_CUSTOM_UPLOAD_FILE_SIZE),
),
'#progress indicator' => 'bar',
'#required' => true,
);
$form['title'] = array(
'#title' => t('Title'),
'#type' => 'textfield',
'#description' => t('Video title, ex. "First Attempt" etc.'),
'#default_value' => '',
'#size' => 60,
'#maxlength' => 64,
'#required' => true,
);
$form['notes'] = array(
'#title' => t('Notes'),
'#type' => 'textarea',
'#description' => t('notes about this video'),
);
$form['team_message'] = array(
'#markup' => 'Your team: <strong>'.$user->name.'</strong> (you)<br/>',
);
$form['teammates'] = array (
'#type' => 'textfield',
'#autocomplete_path' => 'my_custom/teammate/autocomplete',
'#description' => t('Type each teammate\'s username, separated by commas'),
'#element_validate' => array('_my_custom_form_team_validate'),
'#ajax' => array(
'callback' => 'my_custom_form_validate_teammates',
'wrapper' => 'teammates-error',
'method' => 'html',
'effect' => 'none',
'progress' => array (
'message' => NULL,
),
),
);
$form['teammates_verify'] = array (
'#type' => 'markup',
'#prefix' => '<div id="teammates-error">',
'#suffix' => '</div>'
);
if ('' != _are_teammates_valid($form_state['values']['teammates'])) {
$form['teammates']['#error'] = true;
$form['teammates_verify']['#markup'] = '<span class="error">'.t('The following are not valid users: ')._are_teammates_valid($form_state['values']['teammates']).'<pre>'.print_r($form_state,1).'</pre></span>';
}
$form['submit'] = array(
'#type' => 'submit',
'#ajax' => array(
'callback' => 'my_custom_form_callback',
'wrapper' => 'level-form',
'method' => 'replace',
'effect' => 'fade',
'name' => 'submit',
),
'#value' => t('Submit'),
);
return $form;
}
function _my_custom_form_team_validate($element, &$form_state) {
if (!empty($element['#value']) && '' != _are_teammates_valid($element['#value'])) {
form_error($element, t('!teammates are not valid user. Please check spelling.', array('!teammates' => _are_teammates_valid($element['#value']))));
}
}
function my_custom_form_validate($form,&$form_state) {
// validate file upload
// validate teammate list
if (''!=_are_teammates_valid($form_state['values']['teammates'])){
form_set_error('teammates');
}
}
function my_custom_form_validate_teammates($form, &$form_state) {
if ('' != _are_teammates_valid($form_state['values']['teammates'])) {
form_set_error('teammates');
}
return $form['teammates_verify'];
}
function _are_teammates_valid($teammates) {
if ('' != $teammates) {
$team = drupal_explode_tags($teammates);
$bad_usernames = ',';
foreach($team as $possible_teammate) {
$teammate = user_load_by_name($possible_teammate);
if (!$teammate) {
$bad_usernames += $possible_teammate;
}
}
if (2 < strlen($bad_usernames)) {
form_set_error('teammates',t('The following are not valid users: ').substr(2,$bad_usernames).t('. Please recheck spelling.'));
}
}
}
function my_custom_form_callback($form, $form_state) {
my_custom_form_validate($form,$form_state);
if (form_get_errors()) {
return $form;
}
global $user;
$nid = $form_state['values']['nid'];
// $account = user_load($user->uid);
$file = file_load($form_state['values']['video_fid']);
if (!$file) {
$pre['message'] = array(
'#markup' => '<p class="error">'.t('Please upload file first').'</p>',
);
return $pre+$form;
}
$file->status = FILE_STATUS_PERMANENT;
file_save($file);
// TODO change this file_usage_add() call to reflect current module ownership - see http://api.drupal.org/api/drupal/includes!file.inc/function/file_usage_add/7
file_usage_add($file, 'user', 'user', $user->uid);
if (!file_save($file)) {
return t('There was an error uploading the file');
}
$team = array_map('user_load_by_name',drupal_explode_tags($form_state['values']['teammates']));
array_unshift($team, $user);
foreach ($team as $teammate) {
$vnid = _make_video_node($teammate->uid,$form_state['values']['title'],$form_state['values']['notes'],$form_state['values']['nid'],$file);
_make_completion_node($teammate->uid, $form_state['values']['title'],$form_state['values']['notes'],$vnid,$form_state['values']['nid']);
}
if (_my_custom_form_completes($nid, $team)) {
drupal_set_message('Level Completed');
return '<h2>'.t('Level completed!').'</h2>';
}
drupal_set_message('Error Completing Level');
return '<h2>'.t('Error Completing Level').'</h2>';
}