Drupal Ajax Forms - drupal

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'];
}

Related

Drupal login form customize

Hi i have used this code
<?php
$elements = drupal_get_form("user_login");
$form = drupal_render($elements);
echo $form;
?>
to get the default Drupal login form for my site but I need to customize the HTML, I have found some pages in module/users but did not understand how to customize the structure.
The user login form for Drupal is built by the user_login function in user.module using Drupal Form API. If you need to customize it, you should do it using hook_form_alter() in your module
function YOUR_MODULE_NAME_form_alter(&$form, &$form_state, $form_id) {
if ($form_id=='user_login') {
// YOUR CUSTOM CODE FOR THE FORM GOES HERE
}
}
** EDIT, AFTER YOUR COMMENT **
You don't need to call the YOUR_MODULE_NAME_form_alter() function: Drupal does that for you via the hook mechanism everytime it needs to build a form, and, when $form_id=='user_login', it modifies the login form to allow your customization. The way Drupal does that is discussed in detail in drupal.org, just follow the link I wrote at the beginning of this answer.
The user login form is declared this way in user.module:
// Display login form:
$form['name'] = array('#type' => 'textfield',
'#title' => t('Username'),
'#size' => 60,
'#maxlength' => USERNAME_MAX_LENGTH,
'#required' => TRUE,
);
$form['name']['#description'] = t('Enter your #s username.', array('#s' => variable_get('site_name', 'Drupal')));
$form['pass'] = array('#type' => 'password',
'#title' => t('Password'),
'#description' => t('Enter the password that accompanies your username.'),
'#required' => TRUE,
);
$form['#validate'] = user_login_default_validators();
$form['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Log in'));
The $form array is passed by reference to your hook_form_alter() before being rendered, allowing for customization. So, let's say that you want to change the label of the textfield for the user name from "Username" to "Name of the User", you write
$form['name']['#title'] = t("Name of the User");
in your custom code. If you want to add another field to the form (a textarea, for example), you do
$form['otherfield'] = array(
'#title' => t('My new custom textarea'),
'#type' => 'textarea',
'#description' => t("A description of what this area is for"),
'#cols' => 10,
'#rows' => 3,
'#weight' => 20,
);
and Drupal will add the field to the user login form.
There are many different kind of fields and properties that you can customize this way: I encourage you to fully read the Form API documentation. This way you let Drupal take care of form generation, translation, rendering, validation and submission, also permitting to other modules to manipulate your form if needed.
I hope it's clear, have a good day.
use this in template.php
function themename_theme() {
$items = array();
$items['user_login'] = array(
'render element' => 'form',
'path' => drupal_get_path('theme', 'corporateclean') . '/templates',
'template' => 'user-login',
);
and create a template folder and within that create a file user-login.tpl.php and in this file you can put your html and could customize drupal login

Only partial theming of custom form

I've constructed a custom module to create a form. Now I'm stuck on the theming. I already have a CSS stylesheet for the form, since my company is part of the government and they have a preset branding. So I wanted to change the HTML used by the default form theme functions of Drupal thus implementing the correct style.
But only the form-tag of the form gets rendered. The fieldset and elements are not rendered. When the theme functions are removed the default theming kicks in and the form renders normally (but of course without the requested theming).
What I have tried so far:
Added a hook_theme function to add theme functions
function publicatieaanvraagformulier_theme() {
return array(
'publicatieaanvraagformulier_form' => array(
'arguments' => array("element" => NULL)
),
'publicatieaanvraagformulier_fieldset' => array(
'arguments' => array("element" => NULL)
),
'publicatieaanvraagformulier_form_element' => array(
'arguments' => array(
"element" => NULL,
"value" => NULL
)
)
);
}
Added ['#theme'] to the form-element, fieldset-element and the form-elements
$form['#theme'] = "publicatieaanvraagformulier_form";
$form['groep'] = array(
'#title' => t("Please fill in your details"),
'#type' => "fieldset",
'#theme' => "publicatieaanvraagformulier_fieldset"
);
$form['groep']['organisatie'] = array(
'#title' => t("Organization"),
'#type' => "textfield",
'#attributes' => array("class" => "text"),
'#theme' => "publicatieaanvraagformulier_form_element"
);
Added the actual theme function based on the default ones in form.inc
function theme_publicatieaanvraagformulier_form($element) {
function theme_publicatieaanvraagformulier_fieldset($element)
function theme_publicatieaanvraagformulier_form_element($element, $value)
I haven't included the code of these functions because even with the default themefunctions code, they don't work. Therefor I assume they are not the source of the problem.
The form is called
//Get the form
$form = drupal_get_form('publicatieaanvraagformulier');
//Add messages
$errors = form_get_errors();
if (!empty($errors)) {
$output .= theme("status_messages","error");
}
//Show form
$output .= $form;
return $output;
I haven't found similar 'complicated' examples of theming a form, but have pieced together the former from books and online searches.
Hopefully someone has an answer to this problem (point out the mistake I made).
Greetings
Jeroen

How to access form data in hook_form_validate() in drupal 7

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'].

Drupal FAPI form calls callback twice

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));
?>

hook_load/hook_view not called

I have a module with four node types declared. My problem is, hook_load, hook_view is never called. I used drupal_set_message to find out if certain hook is being called. And I found out hook_load, hook_view isn't. Just to give you clear picture, here's my structure of hook_load
HERE'S UPDATED ONE
function mymodule_node_info(){
return array(
'nodetype1' => array(
'name' => t('nodetype1'),
'module' => 'mymodule_nodetype1',
'description' => t('....'),
'has_title' => TRUE,
'title_label' => t('Title'),
'has_body' => TRUE,
'body_label' => t('Body'),
),
'nodetype2' => array(
......
'module' => 'mymodule_nodetype2',
......
),
'nodetype3' => array(
......
'module' => 'mymodule_nodetype3',
......
),
'nodetype4' => array(
......
'module' => 'mymodule_nodetype4',
.......
),
);
}
function mymodule_nodetype1_load($node){
$result = db_query('SELECT * from {nodetype1table} WHERE vid = %d'
$node->vid
);
drupal_set_message("hook_load is provoked.","status");
return db_fetch_object($result);
}
I don't know why it is not called. I wrote this code base on drupal module writing book and follow the instructions. I've tried sample code from that book and it works ok. Only my code isn't working. Probably because of multiple node types in one module. Any help would be highly appreciated.
Your code doesn't work because hook_load() and hook_view() aren't module hooks: they're node hooks. The invocation is based off of content type names, not module names.
So, first you need to have declared your content types using hook_node_info():
function mymodule_node_info() {
$items = array();
$items['nodetype1'] = array(
'name' => t('Node Type 2'),
'module' => 'mymodule_nodetype1',
'description' => t("Nodetype 1 description"),
);
$items['nodetype2'] = array(
'name' => t('Node Type 2'),
'module' => 'mymodule_nodetype2',
'description' => t("Nodetype 2 description"),
);
$items['nodetype3'] = array(
'name' => t('Node Type 2'),
'module' => 'mymodule_nodetype3',
'description' => t("Nodetype 3 description"),
);
return $items;
}
Then, you need to use the name of the module you specified for each content type declared in hook_node_info() for your node hooks. That is, mymodule_nodetype1_load(), mymodule_nodetype2_view(), etc.
Edit
If you're trying to have a non-node based module fire when a node is viewed or loaded, you need to use hook_nodeapi():
function mymodule_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
switch ($op) {
case 'view':
mymodule_view_function($node);
break;
case 'load':
mymodule_load_function($node);
break;
}
}
Replace mymodule_load_function() and mymodule_load_function() with your own custom functions that are designed to act on the $node object.
Edit 2
Besides the syntax error in your hook_load() implementations, there's a piece of your code outside of what you're providing that's preventing the correct invocation. The following code works (if you create a nodetype1 node, the message "mymodule_nodetype1_load invoked" appears on the node): perhaps you can compare your entire code to see what you're missing.
function mymodule_node_info() {
return array(
'mymodule_nodetype1' => array(
'name' => t('nodetype1'),
'module' => 'mymodule_nodetype1',
'description' => t('....'),
'has_title' => TRUE,
'title_label' => t('Title'),
'has_body' => TRUE,
'body_label' => t('Body'),
),
'mymodule_nodetype2' => array(
'name' => t('nodetype2'),
'module' => 'mymodule_nodetype2',
'description' => t('....'),
'has_title' => TRUE,
'title_label' => t('Title'),
'has_body' => TRUE,
'body_label' => t('Body'),
),
);
}
function mymodule_nodetype1_form(&$node, $form_state) {
// nodetype1 form elements go here
return $form;
}
function mymodule_nodetype2_form(&$node, $form_state) {
// nodetype2 form elements go here
return $form;
}
function mymodule_nodetype1_load($node) {
$additions = new stdClass();
drupal_set_message('mymodule_nodetype1_load invoked');
return $additions;
}
function mymodule_nodetype2_load($node) {
$additions = new stdClass();
drupal_set_message('mymodule_nodetype2_load invoked');
return $additions;
}
If you're not reseting your environment after changes to your module, you might be running into caching issues. You should test your code in a sandbox environment that can be reset to a clean Drupal installation to ensure you're not focusing on old cruft from previous, incorrect node implementations.
Additionally, you should only be using hook_nodeapi() if you are trying to act on content types that are not defined by your module. Your content types should be using the node hooks (hook_load(), hook_view(), etc.).
Finally, it may be the case that you're using the wrong hooks because you're expecting them to fire in places they are not designed to. If you've gone through everything above, please update your post with the functionality you're expecting to achieve and where you expect the hook to fire.
I found the culprit why your code doesn't work. It's because I was using the test data created by the old codes. In my old codes, because of node declaration inside hook_node_info uses the same module value, I could only create one hook_form implementation and use "switch" statement to return appropriate form. Just to give you clear picture of my old codes-
function mymodule_node_info(){
return array(
'nodetype1' => array(
.....
'module' => 'mymodule',
.....
),
'nodetype2' => array(
......
'module' => 'mymodule',
......
),
.......
);
}
function mymodule_form(&$node, $form_state){
switch($node->type){
case 'nodetype1':
return nodetype1_form();
break;
case 'nodetype2':
return nodetype2_form();
break;
.....
}
}
When I created new data after I made those changes you have provided, hook_load is called. It works! I've tested several times(testing with old data created by previous code and testing with new data created after those changes) to make sure if that's the root cause and, I got the same result.I think drupal store form_id or module entry value of node declaration along with data and determine the hook_load call. That's probably the reason why it doesn't think it's a data of this node and thus hook_load isn't invoked.
And Thank you so much for your help.

Resources