Hello,

For my site, I have to create a custom form in a custom template. It is not in a custom block, but in a custom tpl-file. I have searched the internet for a solution, but or the form is not shown or the fields are shown, but not in a < form > tag. This way, the submit-button does not work. When I render the fields in a self-written form-tag, the validate function and submit-function don't work.

Can someone help me?

TPL-File

        $form = _odisee_forms($form, $dag, $datum, $uur, $campussen);
        $form['infodag'] = form_process_checkboxes($form['infodag']);
        $formulier = drupal_get_form('infodagen-block-form');
        print '<form id="'.$formulier['#id'].'" accept-charset="UTF-8" method="'.$formulier['#method'].'" action="'.$formulier['#action'].'">'; 
        print drupal_render_children($form); 
        //print render($form);
        print render($formulier['form_id']);
        print render($formulier['form_build_id']);
        print render($formulier['form_token']);
        print '</form>';

forms.inc

function _odisee_forms($type, $dag, $datum, $uur, $campussen) {
  $form = array();
  foreach ($campussen as $key => $campus) {
  $infomoment[] = t($dag[$key])." ".$datum[$key]. " @ " .$campus. " om ".$uur[$key];
  }
  $form['#id'] = 'infodagen-block-form';
  $form['infodag'] = array(
    '#type' => 'checkboxes',
    '#options' => $infomoment,
    '#required' => TRUE,
  );
  $form['voornaam'] = array(
    '#type'  => 'textfield',
    '#title' => t('<img src="/sites/all/modules/custom/odisee_forms/images/icon.png" class="icon">'),
    '#size'  => 15,
    '#attributes' => array(
      'placeholder' => array('Voornaam'),
      'class' => array('breed')
    ),
    '#required' => TRUE,  
  ); 
  $form['naam'] = array(
    '#type'  => 'textfield',
    '#title' => t('<img src="/sites/all/modules/custom/odisee_forms/images/icon.png" class="icon">'),
    '#size'  => 15,
    '#attributes' => array(
      'placeholder' => array('Naam'),
      'class' => array('breed')
    ),
    '#required' => TRUE,  
  );
  $form['emailadres'] = array(
    '#type' => 'textfield', 
    '#title' => t('<img src="/sites/all/modules/custom/odisee_forms/images/arroba-symbol.png" class="icon">'),
    '#size' => 20, 
    '#maxlength' => 128, 
    '#required' => TRUE,
    '#attributes' => array(
      'placeholder' => array('E-mailadres'),
      'class' => array('breed')
    ),
  );
  $form['submit'] = array(
    '#type'  => 'submit',
    '#value' => t('Schrijf in!'),
    '#attributes' => array('class' => array('button')),
    '#submit' => array('_odisee_form_submit'),
    '#validate' => array('_odisee_form_validate'),
  );
  return $form;
}


function _odisee_forms_validate($form_id, &$form, &$form_state) {
  dpm($form_state, "state");
  dpm($form);
}

function _odisee_forms_submit($form, &$form_state) {
}

Comments

mmerrill219’s picture

Jaypan’s picture

You need to create a preprocess function for your form.

function THEMENAME_preprocess_THEMEKEY(&$vars)
{
  $form = drupal_get_form(FORMNAME);
  $vars['my_form'] = drupal_render($form);
}

Now in your template file you can print your form:

print $my_form;
carlovdb’s picture

Hello,
Thank you for your answer.
So in my case, which themekey do I use? Is it THEMENAME_preprocess_forms(&$vars) ?

Jaypan’s picture

You said you're using a custom template. Please show the hook_theme() implementation you are using to register that template. That will help me tell you the THEMEKEY

carlovdb’s picture

Yes, I have my own custom template(theme), but no hook_theme

Jaypan’s picture

How are you adding the template file to the site then?

carlovdb’s picture

Sorry, I meant no specific hook_theme for the form.

function odisee_theme($existing, $type, $theme, $path) {
  return array(
    'odisee_header' => array(
      'template' => 'odisee-header',
      'arguments' => array(
        'info' => NULL,
      ),
      'path' => drupal_get_path('module', 'odisee') . '/theme/templates',
    ),
    'odisee_newsletter' => array(
      'template' => 'odisee-newsletter',
      'arguments' => array(
        'info' => NULL,
      ),
      'path' => drupal_get_path('module', 'odisee') . '/theme/templates',
    ),
    'odisee_addresses' => array(
      'template' => 'odisee-addresses',
      'arguments' => array(
        'info' => NULL,
      ),
      'path' => drupal_get_path('module', 'odisee') . '/theme/templates',
    ),
    'odisee_block_vierkant_2_2' => array(
      'template' => 'odisee-block-vierkant-2-2',
      'arguments' => array(
        'info' => NULL,
      ),
      'path' => drupal_get_path('module', 'odisee') . '/theme/templates',
    ),
    'odisee_footer' => array(
      'template' => 'odisee-footer',
      'arguments' => array(
        'info' => NULL,
      ),
      'path' => drupal_get_path('module', 'odisee') . '/theme/templates',
    ),
  );
}
Jaypan’s picture

Sorry, I meant no specific hook_theme for the form.

Ok, so how are you adding the template to the site? How is it being included? And what is the template name?

carlovdb’s picture

I use field_collections in my site, maybe it is important to mention.

The template where I want to show the form is: odisee-block-vierkant-2-2.tpl.php

It is included in the field-collection-item--field-dynamic-blocks.tpl.php

<!-- vierkant 2x2 -->
    <?php
      $info = new stdClass();
      $info->fields = 'standard3_block1';
      $info->content = $content;
      $info->node = $node;
      print theme('odisee_block_vierkant_2_2', array('info' => $info,));
    ?>
Jaypan’s picture

Ok, then go back to my original post about the preprocess function, and you need to use:

function THEMEKEY_preprocess_odisee_block_vierkant_2_2(&$vars)

Where THEMEKEY is the machine name of your theme.

carlovdb’s picture

When I do that, the form is created, but the input fields are not shown. That was my original problem. :(

Than I get this as HTML

<form action="/xxxxx" method="post" id="odisee-forms--2" accept-charset="UTF-8"><input name="form_build_id" value="form-xt7vpR3eXJqKsmJW2Mg-T1u5H6Ewsm1bRB5WYq7DDNc" type="hidden">
<input name="form_token" value="mPSBoz4AiMqdSYoYZASp9uydu5NuFnNCTjaa2BFp70A" type="hidden">
<input name="form_id" value="odisee-forms" type="hidden">
</form>
Jaypan’s picture

At the start of your form definition, you need to call form_load_include(), since your form is not in the .module file.

carlovdb’s picture

Am I doing something wrong? Because that has no result..
At the end I have form_load_include($form_state, 'inc', 'odisee_forms');

function odisee_forms($type, $dag, $datum, $uur, $campussen) {


  $form = array();
  foreach ($campussen as $key => $campus) {
  $infomoment[] = t($dag[$key])." ".$datum[$key]. " @ " .$campus. " om ".$uur[$key];
  }

  $form['infodag'] = array(
    '#type' => 'checkboxes',
    '#options' => $infomoment,
    '#required' => TRUE,
  );
  $form['voornaam'] = array(
    '#type'  => 'textfield',
    '#title' => t('<img src="/sites/all/modules/custom/odisee_forms/images/icon.png" class="icon">'),
    '#size'  => 15,
    '#attributes' => array(
      'placeholder' => array('Voornaam'),
      'class' => array('breed')
    ),
    '#required' => TRUE,  
  ); 
  $form['naam'] = array(
    '#type'  => 'textfield',
    '#title' => t('<img src="/sites/all/modules/custom/odisee_forms/images/icon.png" class="icon">'),
    '#size'  => 15,
    '#attributes' => array(
      'placeholder' => array('Naam'),
      'class' => array('breed')
    ),
    '#required' => TRUE,  
  );
  $form['submit'] = array(
    '#type'  => 'submit',
    '#value' => t('Schrijf in!'),
    '#attributes' => array('class' => array('button')),
    '#submit' => array('_odisee_form_submit'),
    '#validate' => array('_odisee_form_validate'),
  );
  form_load_include($form_state, 'inc', 'odisee_forms');
  return $form;
}
Jaypan’s picture

Assuming your module is named odisee_forms, and that your include file is named forms.inc, you need this:

  form_load_include($form_state, 'inc', 'odisee_forms', 'forms');
carlovdb’s picture

I am really sorry. But I still get an empty form :(

Jaypan’s picture

Please show all your current code.

carlovdb’s picture

In sites/all/themes/odisee/templates I have: field-collection-item--field-dynamic-blocks.tpl.php

<?php elseif ($type_row == 'standard3'): 
      $info = new stdClass();
      $info->fields = 'standard3_block1';
      $info->content = $content;
      $info->node = $node;
      print theme('odisee_block_vierkant_2_2', array('info' => $info,));
    
        $info = new stdClass();
        $info->fields = 'standard3_block2';
        $info->content = $content;
        $info->extraclass = 'col-6';
        print theme('odisee_block_vierkant_1_4', array('info' => $info,));
      
        $info = new stdClass();
        $info->fields = 'standard3_block3';
        $info->content = $content;
        $info->extraclass = 'col-6';
        print theme('odisee_block_vierkant_1_4', array('info' => $info,));
      
        $info = new stdClass();
        $info->fields = 'standard3_block4';
        $info->content = $content;
        $info->extraclass = 'col-6';
        print theme('odisee_block_vierkant_1_4', array('info' => $info,));
      
        $info = new stdClass();
        $info->fields = 'standard3_block5';
        $info->content = $content;
        $info->extraclass = 'col-6';
        print theme('odisee_block_vierkant_1_4', array('info' => $info,));
      

?>

Based on which field collection type they choose I print a new template
In odisee.module I have an odisee_theme

    'odisee_block_vierkant_2_2' => array(
      'template' => 'odisee-block-vierkant-2-2',
      'arguments' => array(
        'info' => NULL,
      ),
      'path' => drupal_get_path('module', 'odisee') . '/theme/templates',
    ),

The form should only be shown in odisee_block_vierkant_2_2
elseif ($type_row == 'form'):

    $type = trim(render($info->content['field_' . $info->fields .'_form']));
    $form = $info->content['field_' . $info->fields .'_form'][0]['#markup'];
  
print $messages;
if($form == 'Infodagen'):
          $opleiding = node_load($info->node->nid);
          $infodagen = _odisee_get_related_nodes($opleiding, 'infodag', 'opleiding');
        
 foreach ($infodagen as $key => $infodag){
            /* Bundel de campussen en data */           
            foreach ($infodag->field_campus['und'] as $key => $value) {
              /* Controleer of de datum in het verleden ligt */
              $infodatum = date( "d.m.Y", strtotime($infodag->field_datum['und'][0]['value']));
              $infodatumdag = date( "l", strtotime($infodag->field_datum['und'][0]['value']));
              $infouur = date( "H:i", strtotime($infodag->field_datum['und'][0]['value']));
              $vandaag = date( "d.m.Y", time());
              if(strtotime($vandaag) < strtotime($infodatum)){
                $datum[] = $infodatum;
                $uur[] = $infouur;
                $dag[] = $infodatumdag;
                $campus = node_load($value['target_id']);
                $campussen[] = $campus->title;
              }
            }
        }
         /* Maak het form */    
        $form = odisee_forms($form, $dag, $datum, $uur, $campussen);
        /* functie om checkboxen te genereren */    
        $form['infodag'] = form_process_checkboxes($form['infodag']);
        /* functie om selectlist correct te genereren */    
        /* Geen geslacht nodig */
        /* $form['geslacht'] = form_process_select($form['geslacht']); */
        print("<h2>Schrijf je in voor de infodag</h2>");
        $formulier = drupal_get_form('odisee-forms');
        dpm($formulier, "formulier");
        dpm($form, "form");
        /*dpm(array_keys(theme_get_registry()));*/
        print '<form id="'.$formulier['#id'].'" accept-charset="UTF-8" method="'.$formulier['#method'].'" action="'.$formulier['#action'].'">'; 
        print drupal_render_children($form); 
        //print render($form);
        print render($formulier['form_id']);
        print render($formulier['form_build_id']);
        print render($formulier['form_token']);
        print '</form>';

        print $my_form;

        

endif;

endif;

For the form, I have these files
odisee_forms.module


/**
 * Implements hook_init().
 */
function odisee_forms_init() {
  // Loads includes
  module_load_include('inc', 'odisee_forms', 'includes/functions');
  module_load_include('inc', 'odisee_forms', 'includes/forms');
}

functions.inc

function _odisee_get_related_nodes($node, $type, $target_type) {
  $query = new EntityFieldQuery();
  $query
    ->entityCondition('entity_type', 'node', '=')
    ->propertyCondition('status', 1)
    ->propertyCondition('type', $type, '=')
    ->fieldCondition('field_' . $target_type, 'target_id', $node->nid);
  $results = $query->execute();

  $nodes = node_load_multiple($results['node'], array('type' => $type));

  return $nodes;

}

forms.inc


function odisee_forms($type, $dag, $datum, $uur, $campussen) {
 /**
 * Prepare a simple form to add an entry, with all the interesting fields.
 * Per campus tonen we de keuze
 */

  $form = array();
  foreach ($campussen as $key => $campus) {
  $infomoment[] = t($dag[$key])." ".$datum[$key]. " @ " .$campus. " om ".$uur[$key];
  }
  //$form['#id'] = 'infodagen-block-form';
  $form['infodag'] = array(
    '#type' => 'checkboxes',
    '#options' => $infomoment,
    '#required' => TRUE,
  );
  $form['voornaam'] = array(
    '#type'  => 'textfield',
    '#title' => t('<img src="/sites/all/modules/custom/odisee_forms/images/icon.png" class="icon">'),
    '#size'  => 15,
    '#attributes' => array(
      'placeholder' => array('Voornaam'),
      'class' => array('breed')
    ),
    '#required' => TRUE,  
  ); 
  $form['naam'] = array(
    '#type'  => 'textfield',
    '#title' => t('<img src="/sites/all/modules/custom/odisee_forms/images/icon.png" class="icon">'),
    '#size'  => 15,
    '#attributes' => array(
      'placeholder' => array('Naam'),
      'class' => array('breed')
    ),
    '#required' => TRUE,  
  );
  $form['emailadres'] = array(
    '#type' => 'textfield', 
    '#title' => t('<img src="/sites/all/modules/custom/odisee_forms/images/arroba-symbol.png" class="icon">'),
    '#size' => 20, 
    '#maxlength' => 128, 
    '#required' => TRUE,
    '#attributes' => array(
      'placeholder' => array('E-mailadres'),
      'class' => array('breed')
    ),
  );
  $form['submit'] = array(
    '#type'  => 'submit',
    '#value' => t('Schrijf in!'),
    '#attributes' => array('class' => array('button')),
    '#submit' => array('_odisee_form_submit'),
    '#validate' => array('_odisee_form_validate'),
  );

  form_load_include($form_state, 'inc', 'odisee_forms', 'forms');
  return $form;
}


function _odisee_forms_validate($form_id, &$form, &$form_state) {
  dpm($form_state, "state");
  dpm($form);
}

function _odisee_forms_submit($form, &$form_state) {
}



function odisee_preprocess_odisee_block_vierkant_2_2(&$vars){
  $form = drupal_get_form('odisee-forms');
  $vars['my_form'] = drupal_render($form);
}
Jaypan’s picture

I see three major problems.

1) drupal_get_form('odisee-forms');
Your form is called odisee_forms() not odisee-forms(). You are calling the incorrect form name.

2) function odisee_forms($type, $dag, $datum, $uur, $campussen)

Your form definition does not declare $form and &$form_state as the first arguments. All form definitions require these two arguments.

3) form_load_include($form_state, 'inc', 'odisee_forms', 'forms');

Looking at the rest of your code, it appears you should be using includes/forms as the last argument.

carlovdb’s picture

Oh my god. Three stupid errors. (ashamed)
I was changing my code so much that I overlooked these errors.

Thank you for your major help!

carlovdb’s picture

Sorry for this new question Jaypan.

Now I have a strange thing going on with the submit- and validation handler.
When I don't fill in the fields and I click on the submit-button. The page reloads, but the message of the fields being required is not shown. When I hit the submit-button again, the message of required fields is shown.

But it seems that it is one step behind.
For example:
- No field is filled in and I hit the submit button, nothing happens.
- I fill in 1 field and I hit the submit button, the message of required fields comes for the tree fields. This is incorrect, because I have 1 field filled in.
- I hit the submit button, the message of 2 fieds are not filled is is correct.

Nothing further happened to the code, just some css issues.

Jaypan’s picture

Are you defining the form inside the template file itself?

carlovdb’s picture

I define my form in forms.inc.

function odisee_preprocess_odisee_block_vierkant_2_2(&$vars){
  $form = drupal_get_form('odisee_forms');
  $vars['my_form'] = drupal_render($form);
}

in odisee-block-vierkant-2-2.tpl.php I print the form
print $my_form;

in forms.inc, I also create the form

function odisee_forms($type, $dag, $datum, $uur, $campussen, $form, &$form_state) {
 /**
 * Prepare a simple form to add an entry, with all the interesting fields.
 * Per campus tonen we de keuze
 */

  $form = array();
  foreach ($campussen as $key => $campus) {
  $infomoment[] = t($dag[$key])." ".$datum[$key]. " @ " .$campus. " om ".$uur[$key];
  }
  //$form['#id'] = 'infodagen-block-form';
  $form['infodag'] = array(
    '#type' => 'checkboxes',
    '#options' => $infomoment,
    '#required' => TRUE,
  );
  $form['voornaam'] = array(
    '#type'  => 'textfield',
    '#title' => t('<img src="/sites/all/modules/custom/odisee_forms/images/icon.png" class="icon">'),
    '#size'  => 15,
    '#attributes' => array(
      'placeholder' => array('Voornaam'),
      'class' => array('breed')
    ),
    '#required' => TRUE,  
  ); 
  $form['naam'] = array(
    '#type'  => 'textfield',
    '#title' => t('<img src="/sites/all/modules/custom/odisee_forms/images/icon.png" class="icon">'),
    '#size'  => 15,
    '#attributes' => array(
      'placeholder' => array('Naam'),
      'class' => array('breed')
    ),
    '#required' => TRUE,  
  );
  $form['emailadres'] = array(
    '#type' => 'textfield', 
    '#title' => t('<img src="/sites/all/modules/custom/odisee_forms/images/arroba-symbol.png" class="icon">'),
    '#size' => 20, 
    '#maxlength' => 128, 
    '#required' => TRUE,
    '#attributes' => array(
      'placeholder' => array('E-mailadres'),
      'class' => array('breed')
    ),
  );
  $form['submit'] = array(
    '#type'  => 'submit',
    '#value' => t('Schrijf in!'),
    '#attributes' => array('class' => array('button')),
    '#submit' => array('_odisee_form_submit'),
    '#validate' => array('_odisee_form_validate'),
  );

  form_load_include($form_state, 'inc', 'odisee_forms', 'includes/forms');
  return $form;
}
Jaypan’s picture

I don't really have an answer. Try putting everything into the .module file.

Jaypan’s picture

But I do notice that the order of your arguments in your form definition is incorrect.

carlovdb’s picture

Do you mean the creation of my function?
function odisee_forms($type, $dag, $datum, $uur, $campussen, $form, &$form_state) {

Jaypan’s picture

Yes. $form and &$form_state should be the first two arguments in form definitions.

carlovdb’s picture

That did not do the tric.. too bad

carlovdb’s picture

Hello,

I restarted everything and cleaned up my code.

To make the form work, I printed this code in my .tpl.php-file
print drupal_render(drupal_get_form('odisee_forms', $dag, $datum, $uur, $campussen));

Now, the form can be submitted and this code is also executed. (the data is saved in the database).

There is 1 problem. Can you help me?
The error messages (status_messages) from the validation-function are not shown. Even if I use the standard validation-function. (The only thing that needed to be checked is the field is filled in. #required)

If I try to do it with ajax, nothing happens. This is what I added in forms.inc

  $form['submit']['#ajax'] = array(
    'callback' => 'odisee_ajax_subscribe_callback',
    'wrapper' => 'odisee-ajax-subscribe-form',
  );

function odisee_ajax_subscribe_callback($form, &$form_state) {
  if (form_get_errors()) {
    $form_state['rebuild'] = TRUE;
  	$commands = array();
  	$commands[] = ajax_command_prepend(NULL, theme('status_messages'));  
    return array('#type' => 'ajax', '#commands' => $commands);
  } 
  else {
    $system_message = drupal_get_messages();
    return t('Thank you for your submission!');
  }
}

I also tried this

  if (!empty($form_state['input']['email'])) {
    return 'Subscribed !';
  }
  else {
    return $form;
}
Jaypan’s picture

Try changing this:

  if (form_get_errors()) {

To this:

 if(drupal_get_messages('error', FALSE)) {
carlovdb’s picture

Hello,

That doesn't change a thing. It looks like the form does not reload. The site does not display the messages also.

kind regards.

carlovdb’s picture

To be sure, the callback is being called. I tested it with a javascript alert.

Forms.inc - callback function

/**
 * Callback for heymp_form_listserv_subscribe_form_alter
 */
function heymp_ajax_listserv_subscribe_callback($form, &$form_state) {
  if (form_get_errors()) {
    $form_state['rebuild'] = TRUE;
  	$commands = array();
  	$commands[] = ajax_command_prepend(NULL, theme('status_messages'));
	$commands[] = array(
	    'command' => 'your_js_callback', // the name of your javascript callback
	    'value1'  => 'My first value',
	);
	ajax_render($commands);
    return array('#type' => 'ajax', '#commands' => $commands);
  } 
  else {
    $system_message = drupal_get_messages();
    return t('Thank you for your submission!');
  }
}

javascript-file

(function($, Drupal) {
    Drupal.ajax.prototype.commands.your_js_callback = function(ajax, response, status) {
        alert(response.value1);
    }
})(jQuery, Drupal);
Jaypan’s picture

Try this:

$commands[] = ajax_command_prepend("body", theme('status_messages')); 
carlovdb’s picture

No :(
Not succesful.. Like It looks like the site doesn't show the messages

Jaypan’s picture

What happens if you add a message right above that:

drupal_set_message('test message');

If it doesn't show, then the problem isn't in your code that you're showing, it's somewhere else in your system.

carlovdb’s picture

Yes, it shows the messages.

Because of your tip to show in the body, I changed the ajax_command_prepend to the div of the form and it works:

$commands[] = ajax_command_prepend('form#odisee-forms--3', theme('status_messages'));

Drupal Duppy’s picture

Jaypan - I have been building a custom module to pull in some api data, no specific question, just a compliment on your thorough answers and patients with those asking questions. I have found that you have answered questions that I needed answers a number of times. So Thanks.