I have a module in my Drupal 7 application called Feedback. It includes a form for submitting simple feedback. This form is submitted via AJAX, and I’ve already tested and verified the submission handling. In my feedback module, I had originally, via hook_menu, hard-coded the location of this form. I then decided that I wanted it to be more flexible – on a different content-type I have called Landing Page, a user may check a box to include the feedback form. When they do, I simply do a <?= render(drupal_get_form('feedback_form')); ?>, which pulls it in. The feedback form definition lives in a file called feedback.admin.inc, so I had to also put a <?php module_load_include('inc', 'feedback', 'feedback.admin'); ?> to get it to appear.
The form appears, but its AJAX handler is no longer working. Checking outgoing network traffic via Chrome, it appears that the AJAX request is being sent to the generic Drupal AJAX handler. So, when my function feedback_form is called within the feedback module, the form works correctly. When it’s called outside that module, it does not. All of the functions related to this form are in the file feedback.admin.inc, which is being included, so I’m not sure what I’m missing.
For completeness, I’ve included the contents of feedback.admin.inc below, along with how it’s being used in my Landing Page module. Any thoughts? Thanks.
feedback.admin.inc
<?php
function feedback_form($form, &$form_state) {
$form = NULL;
$form['first_name'] = array(
'#type' => 'textfield',
'#title' => 'First Name',
'#required' => TRUE
);
$form['last_name'] = array(
'#type' => 'textfield',
'#title' => 'Last Name',
'#required' => TRUE
);
$form['organization'] = array(
'#type' => 'textfield',
'#title' => 'Organization'
);
$form['email'] = array(
'#type' => 'textfield',
'#title' => 'Email',
'#required' => TRUE
);
$form['telephone'] = array(
'#type' => 'textfield',
'#title' => 'Telephone',
'#required' => TRUE
);
$form['comments'] = array(
'#type' => 'textarea',
'#title' => 'Comments',
'#required' => TRUE
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => 'Submit Feedback',
'#ajax' => array(
'callback' => 'ajax_feedback_form_submit'
)
);
return $form;
}
function ajax_feedback_form_submit($form, &$form_state) {
if (count(form_get_errors())) {
$response_text = '<ul>';
##
## Add each validation error to response text
foreach(form_get_errors() as $element => $error) {
$response_text .= "<li>$error</li>";
}
$response_text .= '</ul>';
$header_text = 'There are errors with your feedback.';
$error_state = TRUE;
##
## Remove message data from session so user is not reminded a second time
unset($_SESSION['messages']['error']);
if (!count($_SESSION['messages'])) {
unset($_SESSION['messages']);
}
} else {
##
## Prepare feedback data for insertion
$data = array(
'first_name' => $form_state['values']['first_name'],
'last_name' => $form_state['values']['last_name'],
'organization' => $form_state['values']['organization'],
'email' => $form_state['values']['email'],
'telephone' => $form_state['values']['telephone'],
'comments' => $form_state['values']['comments'],
'created' => time()
);
##
## Insert feedback record
drupal_write_record('feedback', $data);
$response_text = "Your feedback has been received.";
$header_text = 'Feedback Received';
$error_state = FALSE;
}
##
## Return AJAX response for interpretation by Drupal.ajax JavaScript object
return array(
'#type' => 'ajax',
'#commands' => array(
array(
'command' => 'modal',
'text' => $response_text,
'headerText' => $header_text,
'errorState' => $error_state
)
)
);
}
landing page
<?php module_load_include('inc', 'feedback', 'feedback.admin'); ?>
<div class="column">
<?= render(drupal_get_form('feedback_form')) ?>
</div>
Form submissions happen quite a bit before the theme layer is invoked so calling
module_load_includein a template file is too late. Also I’m pretty sure in a lot of AJAX callbacks the theme layer isn’t invoked at all so the include would never run.Your form function needs to be somewhere Drupal can find it in a normal bootstrap, i.e. in a
.modulefile, or a file explicitly included from a.modulefile. I normally do this by puttingmodule_load_includefunctions at the beginning of the.modulefile itself.