By JosephLavin on
Is their any way to generate a the same form giving it different information on the same page multiple times?
My end goal is to simply have multiple submit buttons on a single page, each one submitting something different.
This all needs to be dynamic, so I can not create a form for each button by hand.
This is what I have for the form set up
/*
* A form, just the add button. Ticker to add is bassed upon variable passed in.
* @return: HTML formatted tab.
*/
function stock_watchlist_add_button_form($ticker=NULL) {
if($ticker) {
$form['Ticker'] = array(
'#type' => 'hidden',
'#value' => $ticker
);
$form['user'] = array('#type' => 'value', '#value' => $GLOBALS['user']->uid);
// the submit buttom
$form['submit'] = array('#type' => 'submit', '#value' => t('Add'));
return $form;
}
}
/*
* Called when the button for stock_watchlist_add_button_form. Puts value into the DB and sets the status message.
* @param: $form_id
* @param: @form_values
*/
function stock_watchlist_add_button_form_submit($form_id, $form_values) {
db_query("INSERT INTO stock_watchlist (user_id, ticker, date_added, close_when_added, scan, date_range) VALUES ('%s', '%s', '%s', '%s', '%s', '%s')" , $form_values['user'], $form_values['Ticker'], date("d/M/Y"), $close,'--','--');
drupal_set_message(t('Added '.$form_values['Ticker'].' to your watchilst!!.'));
}
It works great for the first form I generate, but every one after that generates the same form.
Thanks in advance for the help.
Comments
How are you adding the multiple instances?
It would help to see the code that is adding the various instances of the form and what you mean by they are the same form.
sorry
---
the code
It is in a for loop... but the variables are different each time drupal_get_form is called
and the html does show that each value is different
(is is from a new version I am working on, more variables added.):
What I mean when I say they are the same form:
I am calling the same form, but with different variables attached to it. But I am doing soo multiple times on the same page. which is where the trouble starts.
Thank you for replying.
form id and base
I think you need to give each form a unique form id. You can then use the $form['#base'] attribute so that they all use the same submit and validate functions.
I assume you are defining the forms in the using a custom module-defined form building function?
from the API docs:
See, for example, the node modules's generation of the node form.
---
Work: BioRAFT
Thank you for replying, sill having issues
Here is what I have change around:
I've added the code to change the id, and the code that changes the base so it uses the same submit function.
here is the code calling 3 different instances of the form on the same page:
and here is the html that is generated:
Each form in the html is picking up a unique ID now. But it still is having the same problem. It is only submitting the first set of values.
I noticed the for each form, the form_id and form_token are identical, but I can not figure out how to change that. And I have a feeling that will solve the problem.
Given you can limit how many instances
Given you can limit how many instances then this would be the correct approach, add the following to you module
Then change your declaration of stock_watchlist_add_button_form to add $form_id at the start like this
and everywhere you declare a form field change it so the name uses $form_id (I found this out from the search module)
So for example, change
to
Repeat for all form fields. A side effect of these is any validate or submit function will need to use the same name for the form fields using the form_id passed in to construct the field name.
Then when buildling the forms you need to construct the name used. something like this
Note the forms hook shown at the start needs to be prepared to handle the maximum number of times the foreach() loops through.
Hopefully this will help.
No go for me
This solution does not work for me in my situation.
I do not know how many instanses of the form will be needed once the page is up. It gets its data from a DB that is contently changing. One day, it will display 50 items, the next day 10.
If I could find a way to dynamically set the form_id, so each time it is called it gets a unique form_id it I would be set. But that seems like it is impossible...
Thanks for the help though
Ok, a possible different approach
It seems that instead of having multiple forms you could have one form which each item having a checkbox, something like "pick me" and when they click 'submit' (there is only one of these) and then process the various selected items.
Another way would be not to use forms at all. As shown, the only thing that seems to show is an add button (it is not clear how you know what you are adding if there are multiples). Since the data comes from a database you could build a page with a set of links where the link is of the form 'yourmodule/add/ticker/KEY' where KEY is a key into the table being used. You can even use a graphic for the link so it looks like a button.
Both of these would avoid the need for multiple form id's and hopefully one of the approaches will help you find a solution.
it should work
look at: http://api.drupal.org/api/5/function/node_forms
As long as you know the unique id's of the forms you'll want to generate at any particular moment, this should work. You essentially jsut need something like node_get_types() that returns the current list. There need not be any fixed number.
---
Work: BioRAFT
If you still haven't found
If you still haven't found the solution, I can help you.
Please share
Yes, please share -- I'm having the same problem.
John DeSoi, Ph.D.
http://pgedit.com/
Power Tools for PostgreSQL
Posted here:
Posted here: http://drupal.org/node/64279#comment-218869
like-I-like.
re: True dynamics with hook_forms()
I tried this out and it had the same results - the same form token was being passed to each form, so even though there was a button for each row, only one row was affected.
Maybe I did not follow your instructions properly? When we added a token to each form manually, we started to get a "Validation error". I'm not sure why.
Could you take a look at the code I posted and see if there are any glaring issues? Could you show me how my code could be turned into your version that you posted earlier?
Too bad... Are you sure
Too bad... Are you sure you've read the example? You have not enough code, you need to add your 'hook_forms' and 'your_form_builder' functions.
Possibly it would be easier to use plain html, but it is deprecated from now, so more likely you'll need to migrate to FAPI anyway.
like I like.
Another example
I've posted a lengthy explanation with a fairly simple example of how i resolved this same issue with hook_forms() and using the #submit form directive.
Posted here....
How do I use your example
Hi Dayre,
Thanks for the outline on your website, but I am not sure how to create multiple instances of the 'thing' form elements on one page - which is what I need to do. Can you help further please?
dantina.
Another variation on the same problem...
Ok, I am working on the same project but in a different area. I have a delete button appended to the end of each row of a table (each of which is pulled dynamically from a database). Each button shows up just fine. When I hit any delete button, it only deletes the first entry in the database.
So far, the forms appear to be using the same token, so I set a token manually (see below) but it doesn't seem that I have done it right. When I use the code below, it gives this error:
"Validation error, please try again. If this error persists, please contact the site administrator."
My experience with forms is limited, so I wouldn't be surprised if I'm just creating the form incorrectly. We got a link to this article, but using the solution still yields the same result (which leads me to believe I am doing something else wrong entirely). This is the link: http://drupal.org/node/64279#comment-218869
Can someone have a look at this code? This should be everything that matters, but let me know if you need to see something else.
...
// How we call the form. $symbol_output[$i] changes as we look through an
// array of output values.
$content .= drupal_get_form('stock_watchlist_delete_form', $symbol_output[$i]);
...
function stock_watchlist_delete_form($watchlist_id=NULL)
{
if($watchlist_id)
{
$form['watchlist_id'] = array('#type' => 'hidden', '#value' => $watchlist_id);
$form['form_id'] = array('#type' => 'hidden', '#value' => 'stock_watchlist_delete_form_'.$watchlist_id);
$form['submit'] = array('#type' => 'submit', '#value' => t('Del'));
$form['#id'] = 'stock_watchlist_delete_form_'.$watchlist_id;
// This does NOT seem to be changing anything...
$form['form_token'] = array('#type' => 'token', '#value' => $watchlist_id);
// Token is created (see below) but it gives a validation error when I click the submit button.
$form['#token'] = drupal_get_token($watchlist_id);
// Setting some test output to prove it works (values ARE being passed).
drupal_set_message(t('Watchlist ID: '.$watchlist_id.'.'));
return $form;
}
}
function stock_watchlist_delete_form_submit($form_id, $form_values)
{
//Other actions will go here - this just proves that it works (it doesn't).
drupal_set_message(t('Removed '.$symbol.', (watchlist id: '.$form_values['watchlist_id'].') from your watchlist.'));
}
When created without a token, this part is the same for each array created:
[form_token] => Array
(
[#type] => token
[#default_value] => 274d6474a7c7f394b955b56853e7bfb2
)
Here is what the arrays look like when created WITH a token - the token is different, but something still isn't right about it.
Array
(
[watchlist_id] => Array
(
[#type] => hidden
[#value] => 1
)
[form_id] => Array
(
[#type] => hidden
[#value] => stock_watchlist_delete_form
[#id] => edit-stock-watchlist-delete-form
)
[submit] => Array
(
[#type] => submit
[#value] => Del
)
[#id] => stock_watchlist_delete_form_1
[form_token] => Array
(
[#type] => token
[#default_value] => 274d6474a7c7f394b955b56853e7bfb2
)
[#token] => 7e6f99319135c994a4a44759c781e340
[#parameters] => Array
(
[0] => stock_watchlist_delete_form
[1] => 1
)
[#type] => form
[#post] => Array
(
)
[#programmed] =>
[#description] =>
[#attributes] => Array
(
)
[#required] =>
[#tree] =>
[#parents] => Array
(
)
[#method] => post
[#action] => /watchlist
[#submit] => Array
(
[stock_watchlist_delete_form_submit] => Array
(
)
)
)
A simplier approach
When I want to have any operation like this as part of a table I find it much easier to simply use links for the operations instead of trying to make the form API work in these kind of scenerioes. In this case I would construct a delete link with an approriate path.
simpler... but secure?
That seems like a way to do it. So it would construct a URL and attach all the pertinent variables to it... but what is to prevent someone from simply hitting this URL from an outside source? Or adding their own (incorrect) variables?
Does Druple already protect against this?
You can make it secure
Since you can define the path and write the code that is called for that path you have a lot of control on how secure it. You can determine the access permissions for the path and in the code that handles the link add what ever checks you want.
Agreed. That's how I do it
Agreed. That's how I do it for any listing that might need multiple select. I use links (with access determined by the menu item definition) for each action (edit | delete), and I try to provide a checkbox for multiple record operations. If you're really paranoid, you can check access permissions again once inside the callback function.
http://www.trailheadinteractive.com
--- Featured Projects ---
http://www.montanakitesports.com
http://www.cmrussell.org
http://www.tdandh.com
http://www.cccsmt.org
http://www.universalsemensales.com
http://www.trailheadinteractive.com
One more thought
A really good example of this type of funcionality is the node admin page...
node_admin_nodes in node.module
This shows you how to do multiple select, multiple operations, filters, etc... The filters part is pretty easily removed, leaving a very functional paged listing with individual operations and multiple select operations.
http://www.trailheadinteractive.com
--- Featured Projects ---
http://www.allthingsformom.com
http://www.montanakitesports.com
http://www.cmrussell.org
http://www.tdandh.com
http://www.cccsmt.org
http://www.spectrummedicalinc.com
http://www.universalsemensales.com
http://www.trailheadinteractive.com
the final solution...
in drupal 5, if you change the #value to #default_value in the form's definition, and forget about fiddling with the token, it *works*. bloody hell. (2 hours of our life gone, thanks drupal form api)
That's the right solution.
That's the right solution. You are the man.
same problem
Trying to write a patch for the realtivity module - to allow it to use auto-complete. Generating the form as follows :
Works fine for one form on a page, JS works fine (after the [subform] modification) with more than one on the page. But submit on any form submits the top form.
Getting very frustrated that something so simple should be so maddeningly hard.
a_c_m
Many thanks to cwgordon7 in
Many thanks to cwgordon7 in #drupal for pointing me in the right direction. The solution is as follows :
The key is using http://api.drupal.org/api/function/hook_forms/5 to allow you to create a form with a unique ID (thats a Drupal form id not to be confused with a html id). Lets say (as in my case), you wanted to use the same form for different node types... a good example of doing this is node_forms() http://api.drupal.org/api/function/node_forms/5
My _hook code looked like this :
All i then needed to do was correctly call the form :
And in the form use #base to make sure it submit to my relativity_autocomplete_child_submit function and not relativity_autocomplete_child_$type_submit like so :
Hope this helps someone else :)
a_c_m
Use hook_forms
Quite old query but I think it is better to post it for sake of completion.
Solution lies in using hook_forms effectively. It maps different form ids to same form builder function. Highly effective. Following gives step step by account of the same:
http://api.drupal.org/api/drupal/developer--hooks--core.php/function/hoo...