I have created a custom Drupal module/form that when submitted the action takes you to another page and posts data with it. Pretty standard stuff.
Randomly, the form action changes at random (not set) intervals during the day that are not correlating to anything immediately obvious - for example cron runs. It only happens maybe once or twice a day, so if anyone has any idea what might cause this or point me in the right direction.
Anything anyone feels needs adding, let me know.
The is the custom module code:
/**
* Test form declaration
*/
function test_form($form, &$form_state){
$form['#attributes'] = array('id' => "test-form");
$form['search-field'] = array(
'#type' => 'textfield',
'#title' => t('<span class="highlighted">Test</span>'),
'#attributes' => array(
'class' => array('form-control form-text'),
),
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => 'Search',
'#attributes' => array(
'class' => array('btn btn-default text-hide'),
),
);
return $form;
}
/**
* search form submit
*/
function test_form_submit($form, &$form_state){
$searchQuery = $form_state['values']['search-field'];
$query = array();
if($search <> ''){
$query = array(
'field_geofield_distance[distance]' => '100',
'field_geofield_distance[unit]' => '3959',
'field_geofield_distance[origin]' => $search
);
}
drupal_goto('test-page', array('query' => $query));
}
If your form creates data (let's say a node) possibly you have a redirection on rules when creating a node that with specific values redirects to another page.
Look for rules that are activated when content creation occur or when submission occur.
Also you could have some redirection magic in the top of Drupal, like a wrong configuration of an .htacess file. If your form does the same thing always it should behave the same always. And why it's redirecting to page of old site?
Finally, if the new site have code from the old site the check submission, creation and form altering hooks.
Hope that helps.
Related
I have an issue with multiple AJAX requests modifying a form within drupal 8.
Let me explain - I have been trying to build a quiz module within drupal, and decided to use a widget to create a variable amount of quiz questions, within this question widget is a list of possible answers.
I have created an AJAX button within my question widget which allows answers to be removed and it works the first time it is submitted, but for some reason the second time I run the ajax call the form is reset (like no changes have been made, and no answers have been removed). I have debugged the form array after I have unset an answer, aswell as when the ajax callback is run the second time.
The ajax-enabled button uses the default ajax replace method and I have tried different methods of returning the form (minus an answer) within my AJAX callback including simply unsetting the selected form element and returning the form, aswell as using the AjaxResponse and HtmlCommand classes. I have also tried to rebuild both the form, via formbuilder, and form_state with no joy.
Also each button and answer have unique names/id's.
Here is my widget code (including the button definition):
<?php
/**
* #file
* Contains \Drupal\pp_quiz\Plugin\Field\FieldWidget\QuestionWidget.
*/
namespace Drupal\pp_quiz\Plugin\Field\FieldWidget;
use Drupal\pp_quiz\Controller\QuizController;
use Drupal\pp_quiz\Ajax\AjaxHandler;
use Drupal\Core\Field\WidgetBase;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Form\FormStateInterface;
/**
* Plugin implementation of the 'question_widget' widget
*
* #FieldWidget(
* id = "question_widget",
* label = #Translation("Quiz question widget"),
* field_types = {
* "quizquestion_type",
* },
* )
*/
class QuestionWidget extends WidgetBase
{
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
$ajaxhandler = new AjaxHandler();
$input = $form_state->getUserInput();
//grab answer count from element array (using delta index)
$question = $items->get($delta)->getValue();
$answercount = count(unserialize($question['answer']));
$element['question'] = array(
'#type'=>'text_format',
'#format' => 'normal',
'#title' => gettext('Question'),
'#description' => gettext("The Question Text"),
'#required' => TRUE,
'#element_validate' => array(
array(
'\Drupal\pp_quiz\Controller\QuizController',
'validateQuestion'
),
),
);
$element['answers_description'] = array('#markup' => 'Create answers below and select which are correct by checking boxes');
$tableheader = array(
'answer' => array('data' => t('Answer'), 'field' => 'answer'),
);
for ($i=0; $i<$answercount; $i++) {
$name = "{$delta}answer{$i}";
$options[$name] = array(
'answer' => array(
'data' => array(
'#type'=>'textfield',
//fix for losing answers on addmore button
'#value'=>isset($input[$name]) ? $input[$name] : '',
'#name' => $name,
'#required' => TRUE,
),
),
);
}
$element['answers'] = array(
'#type'=>'tableselect',
'#header' => $tableheader,
'#options' => $options,
);
$element['removeanswer'] = array(
'#type' => 'submit',
'#value' => t('Remove Answer'),
'#name' => "{$delta}removeanswer",
'#questionno' => $delta,
'#attributes' => array(
'class' => array('removeanswer')
),
'#ajax' => array(
'callback' => array(
$ajaxhandler,
'removeAnswerAjax',
),
'wrapper' => 'edit-field-quiz-questions-wrapper',
),
);
$element = array(
'#type' => 'question',
) + $element;
return $element;
}
}
As you can see above, my 'removeanswer' submit button element has an ajax callback to a function called 'removeAnswerAjax' on the class 'AjaxHandler'. Below is the code for this callback:
<?php
/**
* #file
* Contains \Drupal\pp_quiz\Ajax\AjaxHandler.
*/
namespace Drupal\pp_quiz\Ajax;
use \Drupal\pp_quiz\Controller\QuizController;
use \Drupal\pp_quiz\Entities\QuizResults;
use \Drupal\Core\Form\FormStateInterface;
use \Drupal\Core\Ajax\AjaxResponse;
use \Drupal\Core\Ajax\HtmlCommand;
class AjaxHandler {
public function removeAnswerAjax(&$form, FormStateInterface $form_state) {
$questionno = $form_state->getTriggeringElement()['#questionno'];
$response = new AjaxResponse();
//find selected answer for question number (questionno)
foreach($form['field_quiz_questions']['widget'][$questionno]['answers']['#value'] as $answer_key=>$answer) {
unset($form['field_quiz_questions']['widget'][$questionno]['answers']['#options'][$answer]);
unset($form['field_quiz_questions']['widget'][$questionno]['answers']['#default_value'][$answer]);
unset($form['field_quiz_questions']['widget'][$questionno]['answers'][$answer]);
}
$response->addCommand(new HtmlCommand('#edit-field-quiz-questions-wrapper', $form['field_quiz_questions']['widget']));
$form_state->setRebuild();
return $response;
}
}
If anyone could shed any light on why the form is being reset before it is passed as an argument to my ajax callback, I would love you forever :-)
Thanks for reading.
One possible reason that your Ajax doesn't takes effect the second time is rebuilding of the form, in Ajax callback. As you are rebuilding the form using -
$form_state->setRebuild()
When a form is rebuilt, all the field and form ids are suffixed by a random build number. thus the selector is not found and the response is not replaced in DOM.
Try removing the form rebuild.
I'm trying to register an ajax listener to a checkbox on one of my standard node forms. I want to display certain regions of the form only in case, the field is checked. I can get the drupal ajax ecosystem to work, when I use it in a custom form, but I'm unable to make it work on my node forms.
First I hook into form_alter to check if I'm with the node type I want to add the listener for:
function interceptor_form_alter(&$form, &$form_state, $form_id) {
if($form_id === 'film_node_form') {
interceptor_dvd_listener($form, $form_state);
}
}
Then I try to attach the ajax stuff to my checkbox, which name is field_dvd:
function interceptor_dvd_listener(&$form, &$form_state) {
$form['field_dvd'] = array(
'#title' => t('You want to display DVD informations too?'),
'#type' => 'checkbox',
'#ajax' => array(
'callback' => 'interceptor_dvd_listener_callback',
'wrapper' => 'checkboxes-div',
'effect' => 'slide',
'progress' => array('type' => 'none'),
),
);
return $form;
}
The function interceptor_dvd_listener_callback is never called. I try to print some debug information there, but nothing happens...
function interceptor_dvd_listener_callback($form, $form_state) {
data_service_log_object($form);
}
UPDATE
After passing the form variable as reference to interceptor_dvd_listener the ajax callback worked like expected.
Most likely error:
You are not passing $form by reference to interceptor_dvd_listener() function. You are also not using the returned value from this function. Change the function definition to:
function interceptor_dvd_listener(&$form, &$form_state) {
$form['field_dvd'] = array(
'#title' => t('You want to display DVD informations too?'),
'#type' => 'checkbox',
'#ajax' => array(
'callback' => 'interceptor_dvd_listener_callback',
'wrapper' => 'checkboxes-div',
'effect' => 'slide',
'progress' => array('type' => 'none'),
),
);
}
Now see if it works. If it doesn't then, do the following:
Make sure that your custom module name is "interceptor".
Make sure that the id of the form you are modifying is "film_node_form".
Change the function interceptor_form_alter() to:
function interceptor_form_alter(&$form, &$form_state, $form_id) {
if($form_id == 'film_node_form') {
interceptor_dvd_listener($form, $form_state);
}
}
If it still doesn't work, print out $form variable at the end of interceptor_form_alter() function and see if field_dvd has the #ajax key.
You could also use this module (https://www.drupal.org/project/field-conditional-state) instead of writing all this custom code.
This interceptor_dvd_listener_callback() should return value, in documentation:
After form processing is complete, ajax_form_callback() calls the
function named by #ajax['callback'], which returns the form element
that has been updated and needs to be returned to the browser, or
alternatively, an array of custom Ajax commands.
Why don't you use this:
https://api.drupal.org/api/drupal/developer!topics!forms_api_reference.html/7#states
It is drupal 7 standard feature to hide or show some fields when some elements has some states.
I have been searching all day but unable to find any answers - I am sure I am doing it right as worked fine in Drupal 6 and should work fine in Drupal 7.
I want to give a custom theme function to my select element in my form
$form['field_name'] = array(
'#type' => 'select',
'#title' => t('Title Here'),
'#theme' => 'custom_select',
'#options' => $values,
);
I have the theme hook right to declare the new custom theme function but my problem is when using that custom theme function as above I get an empty $variables array which just reads
Array([element] => null)
can anyone see what I may be doing wrong? cleared cache, done everything I can think of - any ideas why Drupal is not passing the element data to the theme function? thanks
well finally figured this one out incase any one else has the problem - make sure you set render element in hook_theme and not variables!
before
function hook_theme(){
return array(
'select_currency' => array(
'variables' => array('element' => null),
'file' => 'module_name.theme.inc',
));
}
after
function hook_theme(){
return array(
'select_currency' => array(
'render element' => 'element',
'file' => 'module_name.theme.inc',
));
}
I was pulling my hair out until I remembered the render element!
I want to render form in drupal separately, item by item.
function form($form){
$form['item1'] = array(
'type' => 'textarea', .........etc
$form['item1'] = array(
'type' => 'textarea', .........etc
$form['submit'] = array(
'type' => 'submit', .........etc
}
$a = drupal_get_form('form');
drupal_render($a['item1']);
drupal_render($a['item2']);
drupal_render($a['submit']);
form is rendered successfully, but it seems that submit button not work (not call submit function)
Any help?
Thanks
You just need to call drupal_render() one more time:
drupal_render($a);
It won't re-render everything you previously rendered.
I am trying to include a Drupal form element in a table I am generating with theme_table/theme('table',..). Specifically, I am trying to include a submit button with an AHAH attached.
Currently, I am just including as one cell in each row a call to drupal_render to render my dynamically generated AHAH element. The button renders fine, but without the AHAH attached.
So, my question is: is there a way to attach an AHAH to something that is just drupal_rendered?
If not, how else can I attach an AJAX/AHAH call to an element in a theme_table-generated table? I need to allow users to perform certain actions on rows of data in the table but need the page to not refresh.
TIA,
Benjy
I believe AHAH only works with drupal_get_form(). You'd have to write the AJAX yourself ( handbook page).
Maybe you could save the return value from drupal_get_form() in a variable and pass it to the theme function?
I think this is sort of a bug but i created a very easy generic workaround :) Solution by Januz did not work for me since the table was used inside a form already and also it's only applicable to very specific use cases and not a generic solution.
You can have a look at the following code and the function i wrote as an example
Notice : You may probably need to modify the code to suit your needs
/**
* #param $form
* #param $form_state
* #param $form_id
*/
function mymodule_form_alter(&$form, &$form_state, $form_id) {
$test_button = array(
'test_button' => array(
'#type' => 'button',
'#value' => t('Add'),
'#name' => 'test_button',
'#id' => 'test_button',
'#weight' => 2,
'#ajax' => array(
'callback' => '_mymodule_ajax_callback',
)
)
);
$form['mytable'] = array(
'#weight' => 1,
'#theme' => 'table',
'#header' => array(
array("data" => "Item"),
),
'#rows' => array(
'data' => array(
array(
'data' => $test_button
),
)
),
);
// This is a work around, ajax elements do not work when used in drupal tables
mymodule_table_ajax_workaround($test_button, $form, $form_state);
}
/**
* Ajax enabled form elements do not work then used inside a drupal table and rendered via theme_table
* This is a workaround to address the issue
* #param $elements
* #param $form
* #param $form_state
*/
function mymodule_table_ajax_workaround($elements, &$form, &$form_state) {
foreach ($elements as $element_name => $element_info) {
drupal_add_js(array('ajax' => array(
$element_name => array(
'callback' => $element_info['#ajax']['callback'],
'event' => 'mousedown',
'keypress' => true,
'prevent' => 'click',
'url' => '/system/ajax',
'submit' => array(
'_triggering_element_name' => $element_name . '_fake',
'_triggering_element_value' => $element_info['#value'],
)
),
)), 'setting');
$form['form_ajax_workaround'][$element_name] = array(
'#name' => $element_name . '_fake',
'#input' => true,
'#value' => $element_info['#value'],
'#ajax' => array(
'callback' => $element_info['#ajax']['callback']
)
);
}
}
You can do this via theme function and table generation. AHAH will work. The only problem is when you have multiple "tables", things start getting hairy.
Short explanation (correct me if I am wrong!): AJAX enabled form elements appear invisible to Drupal's Form API when they remain inside a "#theme" => "table" render array. This is probably due to render() using element_children() which does not look into a table's #header or #rows elements. A way to workaround this is to add dummy elements to the form which are visible to the Form API and bind AJAX events to the original elements to trigger the dummy elements.
I forked Sina Salek's great workaround for Drupal 7, main differences are:
Different form field keys, names and ID's are allowed,
The callback from the JS AJAX settings object is removed since it does not seem to exist in JS,
Added the base path variable to the AJAX URL for sites that are not installed in the web root,
Use "#type" => "value" for the dummy buttons instead of the internal options "#input" => TRUE,
The dummy element is available through the exact same name as the original element, without a "_fake" postfix, since the original elements are invisible to the Form API and the dummy elements do not appear in the DOM,
The full #ajax array is copied to the dummy element instead of just the callback element so other settings (ie. for the throbber) remain.
Allows the user to set custom JS AJAX options per button.
Example of implementing the workaround per AJAX enabled element when building a form:
/**
* My form.
*/
function MY_MODULE_my_form($form, &$form_state) {
// Define button. NB: An ID and name are required!
$my_button = array(
'#type' => 'button',
'#id' => 'test_button',
'#name' => 'test_button',
'#value' => t('Button label'),
'#ajax' => array('callback' => '_MY_MODULE_ajax_callback'),
);
// Call table AJAX workaround function on the button.
MY_MODULE_table_ajax_workaround($my_button, $form);
// Define table.
$form['my_table'] = array(
'#theme' => 'table',
'#header' => array(
array('data' => t('Column header')),
),
'#rows' => array(
'data' => array(
array('data' => $my_button),
)
),
);
return $form;
}
/**
* Workaround for AJAX enabled form elements that remain inside tables.
*
* Problem: AJAX enabled form elements appear invisible to Drupal's Form API
* when they remain inside a #theme => table render array. This is probably due
* to render() using element_children() which does not look into a table's
* #header or #rows elements.
*
* Workaround: Add dummy elements to the form which are visible to the Form API
* and bind AJAX events to the original elements to trigger the dummy elements.
*
* Based on:
* #link http://stackoverflow.com/questions/1981781
*
* Shared at:
* #link http://stackoverflow.com/a/31098784/328272
*
* Another workaround is the render elements using custom theme functions, but
* this seems slightly more complicated and rendered elements are no longer
* alterable.
* #link https://www.drupal.org/node/2101557#comment-7920151
*/
function MY_MODULE_table_ajax_workaround($element, &$form, $js_ajax_options = array()) {
// Add dummy element.
$form['table_ajax_workaround'][$element['#id']] = array(
'#type' => 'value',
'#name' => $element['#name'],
'#value' => $element['#value'],
'#ajax' => $element['#ajax'],
);
// Bind AJAX event to the original element, default properties are used. See
// Drupal.ajax in misc/ajax.js.
$js_setting['ajax'][$element['#id']] = drupal_array_merge_deep(array(
'event' => 'mousedown',
'keypress' => true, // Use lowercase booleans to support IE.
'prevent' => 'click',
'url' => base_path() . 'system/ajax',
'submit' => array(
'_triggering_element_name' => $element['#name'],
'_triggering_element_value' => $element['#value'],
),
), $js_ajax_options);
// Add JS setting.
drupal_add_js($js_setting, 'setting');
}