I have a form which has textfields with default values specified. On submit event, I want these default values to be changed with the new set of values that I am passing. I am using form_set_value($element, $value, $form_state) for this. However it is not updating. Any ideas? My code is
function sample_myform($form_state){
$form['field']['name'] = array(
'#type' => 'textfield',
'#title'=> 'Name: ',
'#maxlength'=> 127,
'#default_value' => param1,
);
$form['field']['placeholder'] = array(
'#type'=> 'value',
'#value' => array(),
);
$form['field']['button1'] = array(
'#type' => 'submit',
'#value' => 'Submit',
);
return $form;
}
function sample_myform_validate($form,&$form_state){
$name2 = $form_state['values']['name'];
form_set_value($form['field']['placeholder'], $name2, $form_state); */
form_set_value($form['field']['name'],'God',$form_state);
$form_state['rebuild'] = true;
}
One thing for sure, $form['field']['placeholder'] will never, ever change since you set #value. Once #value is set, Form API moves on. Be careful though with setting just #default_value on a #type value as that can be tampered with. You can do something like $form_state['placeholder'] = $name2; in validate and use that in the form builder function.
What you try to do with name works in Drupal 7 but I suspect you are in Drupal 6. The validate function overwrites $form_state['values'] just fine but that's not persisted for the form rebuild. Once again, save into $form_state as you need.
Related
I have a form in Drupal that calls an external database in Netezza. Retrieve this data from Netezza lasts about 10 seconds. Then, based on that information I have to build a select control to let the user choose from a list of categories. When the user chooses a category I do another expensive call to Netezza to retrieve more information.
The problem is that for the second interaction (when the user chose a category) the form is reprocessed and therefore doing 2 expensive calls to Netezza, not one as anyone would expect or desire.
Do you know a workaround for this situation? Is there a way to do an ajax call using the Drupal Ajax Framework without rebuilding the entire form?
Thanks.
PD: Reading documentation about the Ajax Framework I guess a solution could be using another path specifiying #ajax['path'], but havenĀ“t fully tested that behavior and will be thankful if you share your experience.
PD2: I would prefer a workaround based on the Drupal Ajax Framework, not in a caching mechanism.
I'd highly recommend you to have a look into Drupal Examples, specially the module called ajax_example.
this is a fast sample code, might not be running, but just to give you the idea
function expensive_form($form, &$form_state) {
$form['category'] = array(
'#title' => t('Cateogry'),
'#type' => 'select',
'#options' => first_expensive_operation(),
'#ajax' => array(
'callback' => 'choose_category_callback',
'wrapper' => 'ajax-div',
// 'method' defaults to replaceWith, but valid values also include
// append, prepend, before and after.
// 'method' => 'replaceWith',
// 'effect' defaults to none. Other valid values are 'fade' and 'slide'.
'effect' => 'slide',
// 'speed' defaults to 'slow'. You can also use 'fast'
// or a number of milliseconds for the animation to last.
// 'speed' => 'slow',
),
);
$form['ajax_fieldset'] = array(
'#title' => t("Ajax Fields"),
// The prefix/suffix provide the div that we're replacing, named by
// #ajax['wrapper'] above.
'#prefix' => '<div id="ajax-div">',
'#suffix' => '</div>',
'#type' => 'fieldset',
'#description' => t('This is where we get automatically updated something'),
);
// this will only be executed on the second run of the form
// when the category is set.
if (isset($form_state['values']['category'])) {
$form['ajax_fieldset']['something'] = array(
'#title' => t('Somethings'),
'#type' => 'select',
'#options' => second_expensive_operation($form_state['values']['category']),
);
}
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Submit'),
);
return $form;
}
/**
* Callback element needs only select the portion of the form to be updated.
* Since #ajax['callback'] return can be HTML or a renderable
* array, we can just return a piece of the form.
*/
function choose_category_callback($form, $form_state) {
return $form['ajax_fieldset'];
}
I have created several custom elements in a module, which work great for grouping several controls in a single form field.
However, I now need to add one that contains a drop-down list. The idea is to have a drop-down list of country codes, and a text field for the phone number.
It displays correctly and looks good until the form is submitted, which results in the error, "An illegal choice has been detected. Please contact the site administrator." This would seem to indicate that Drupal isn't recognising the options as being part of the select control.
Here's my code:
function my_module_element_info() {
$types = array(
'phone' => array(
'#input' => TRUE,
'#process' => array('my_module_phone_process'),
'#element_validate' => array('my_module_phone_validate'),
'#autocomplete_path' => FALSE,
'#theme_wrappers' => array('my_module_inline_form_element'),
),
);
return $types;
}
function my_module_phone_process($element, &$form_state, $complete_form) {
$element['#tree'] = TRUE;
$element['prefix'] = array(
'#type' => 'select',
'#value' => $element['#value']['prefix'] ,
'#options' => $element['#options'],
'#required' => $element['#required'],
);
$element['number'] = array(
'#type' => 'textfield',
'#size' => 20,
'#maxlength' => 40,
'#value' => $element['#value']['number'],
'#required' => $element['#required'],
);
if (isset($element['#attributes'])) {
$element['prefix']['#attributes'] = $element['#attributes'];
$element['number']['#attributes'] = $element['#attributes'];
}
$element['prefix']['#attributes']['class'][] = 'form-phone-prefix';
$element['number']['#attributes']['class'][] = 'form-phone-number';
if (isset($element['#ajax'])) {
$element['prefix']['#ajax'] = $element['#ajax'];
$element['number']['#ajax'] = $element['#ajax'];
}
return $element;
}
function my_module_phone_validate($element) {
if (!preg_match('/^[0-9 ]+$/', $element['#value']['number'])) {
form_error($element['number'], t('Phone number may contain only digits and spaces.'));
}
return $element;
}
Any help getting this working would be greatly appreciated.
Thanks for looking.
James
you can add the following attribute to the element causing this error.
'#validated' => TRUE,
This problem got parked on the back burner for a while, but I got back to it this week.
I think I now understand the reason for the error. If an element has a "#options" property, it is expected to behave like a select control, and one of the options should be submitted. As the field itself is a container for other controls, so has no input directly, there is no posted value matching an entry in "#options" so Drupal flags it as an invalid form submission.
After a lot of trial and error, I hit on something very simple. The "#options" are used to populate the child control, but once it's been populated, they are no longer needed on the parent. So I added a "#after_build" function to the element, and used it to remove the "#options", and it worked perfectly.
function common_pricing_phone_after_build($element, &$form_state) {
unset($element['#options']);
return $element;
}
I have a form implemented from hook_form called simplequiz_form() I want to access its data after submit below is the code I have written but I can't seem to access its data once its submitted. What am I doing wrong ?
function simplequiz_form_validate($form, &$form_state) {
// here is where we will validate the data and save it in the db.
$thid = db_insert('simplequiz')
->fields(array(
'questions' => &$form_state['question'],
**I can't seem to access the value of a field questions**
))
->execute();
return $thid;
}
Below is my implementation of hook_form()
function simplequiz_form($form, &$form_submit)
{
$form['question'] = array(
'#title' => t('Please input your question'),
'#type' => 'text_format',
'#required' => FALSE,
'#description' => t('Here is where you can enter your questions'),
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => 'Submit',
);
return $form;
}
if I use $form_state['values']['question']
I get the below error:
PDOException: SQLSTATE[21S01]: Insert value list does not match column list: 1136 Column count doesn't match value count at row 1: INSERT INTO {simplequiz} (questions) VALUES (:db_insert_placeholder_0_value, :db_insert_placeholder_0_format); Array ( [:db_insert_placeholder_0_value] => [:db_insert_placeholder_0_format] => filtered_html ) in simplequiz_form_submit() (line 245 of /home/vishal/Dropbox/sites/dev/sites/all/modules/simplequiz/simplequiz.module).
it worked using $form_state['values']['question']['value']
It's best practice to use hook_form_validate, just for validation purposes, anything other than validation should be done in hook_form_submit.
Either way they both function almost the same way.
All the form data is stored in $form_state['values'], so to access $form['questions'] values, just use $form_state['values']['questions'].
I am new to writing Drupal forms, and having trouble in what seems the simplest thing of the whole process form namely putting data in a textarea on the form before rendering.
I am using drupal 7
I have all necessary files in the module: i.e. .module, and .info ..
I have used all of these function in my hook_submit() but to no avail.
Form_state['values'][$myElement=]= $myText;
Form_state[$myElement=]= $myText;
form_set_value($form[$myElement], t('$myText'), $form_state);
I flushed the cache before every single attempt:
Nothing seems to work. Here is what is in my submit handler:
mForm_submit(){
//$form_state['values']['sku_output_fieldset']['sku_output'] = t('$gen_sku_txt');
//$form_state['gen_sku']['sku_output_fieldset']['sku_output'] = t('$gen_sku_txt');
//$form['sku_output_fieldset']['sku_output']['#value'] = t('$gen_sku_txt');
//form_set_value($form['sku_output_fieldset']['sku_output'], t('$gen_sku_txt'), $form_state);
//form_set_value($form['sku_output'], t('$gen_sku_txt'), $form_state);
//form_set_value($form['sku_output'], array('rgb' => '123'), $form_state);
//form_set_value($form['sku_output_fieldset']['sku_output'], array('#default_value' => '123'), $form_state);
//form_set_value($form['sku_output_fieldset']['sku_output'], array('#value' => '123'), $form_state);
//form_set_value($form['sku_output_fieldset']['sku_output'], array('value' => '123'), $form_state);
//form_set_value($form['sku_output_fieldset']['sku_output'], array('default_value' => '123'), $form_state);
$form_state['rebuild'] = TRUE;
}
all commented code, is what i have tried and did not work.
Are you building the form with Drupal 7 Form API? This is how I've inserted default text into a textarea in a Drupal form:
$form['formname_fieldname'] = array(
'#default_value' => t('Some default text'),
'#title' => t('Field Title'),
'#type' => 'textarea',
'#required' => FALSE,
'#rows' => 10,
);
Your textarea will be prepopulated with "Some default text"
If you want to change it before rendering, you shouldn't have in a submit function.
You should use hook_form_alter(&$form, &$form_state, $form_id) where the $form being passed in is the variable you can use to edit the form.
First post on stack overflow... so go easy on me!
There doesn't seem to be a suitable solution to the Drupal FAPI multiple callback issue for simple form submissions.
THE PROBLEM: My form, when submitted, adds two entries to the respective database table. Given that there is only one call to add it to the database, I feel it's safe to assume that the query is run twice (hence the dual entries).
The following code may help to provide a basis for a solution. Oh, it's Drupal 7 too, so documentation is still very much D6 centric.
function mymodule_sidebar_form_add_submit(&$form, &$form_state) {
$form_values = $form_state['values'];
$se_title = check_plain(trim($form_values['title']));
$se_link = url(trim($form_values['link']));
$se_content = check_plain(trim($form_values['content']));
$se_image = isset($form_values['image']) ? $form_values['image'] : '';
// The multi-line part below is actually a single line the real code
$query = sprintf("INSERT INTO sidebar_element(title, image_url, content)
VALUES ('%s', '%s', '%s');", $se_title, $se_image, $se_content);
db_query($query);
drupal_set_message(t('Sidebar Element has been added successfully.'));
}
... and my form function contains a submit button:
$form['submit'] = array(
'#value' => t('Add Sidebar'),
'#type' => 'submit',
'#title' => t('Add Sidebar'),
'#submit' => array('mymodule_sidebar_form_add_submit'),
);
I guess the questions I need answered are:
Why is there a double callback in the first place?
Is there a way to identify the first callback?
Thanks in advance to all.
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Save')
);
$form['#submit'] = array('my_form_submit');
And replace
// The multi-line part below is actually a single line the real code
$query = sprintf("INSERT INTO sidebar_element(title, image_url, content)
VALUES ('%s', '%s', '%s');", $se_title, $se_image, $se_content);
db_query($query);
with
// The multi-line part below is actually a single line the real code
$query = "INSERT INTO {sidebar_element} (title, image_url, content)
VALUES ('%s', '%s', '%s')";
db_query($query, $se_title, $se_image, $se_content);
For Drupal 7
// Add the buttons.
$form['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array(
'#type' => 'submit',
'#access' => my_func(),
'#value' => t('Save'),
'#weight' => 100,
'#submit' => array('my_form_submit'),
);
As example read node_form() code
To find out where the second call is coming from, the easiest way is to install devel.module and use ddebug_backtrace() in your submit callback. You might need to disable the HTTP redirecto to see it, too (exit()).
But more importantly, use the API, Luke!
<?php
db_insert('sidebar_element')
->fields(array(
'title' => $se_title,
'image_url' => $se_image,
'content' => $se_content,
))
->execute():
?>
This is how your insert query should look like, what you are doing is insecure!
And for SELECT, use db_query() with named placeholders:
<?php
$result = db_query('SELECT * FROM {sidebar_element} WHERE title = :title', array(':title' => $something));
?>