I've been trying to figure this out for the past day or two: the correct way to pre-populate a Drupal 7 form's elements with arbitrary values once it has already been created and submitted once. During the submit handler, I have logic in there that decides whether to redisplay the form with new values (that I come up with, based on the user's input), or do something else. The scenario relevant to this post is redisplaying the form with new values, derived programmatically in the ..._submit()
function, to pre-populate some of its fields.
Sounds easy, right? Seems to be straightforward and a pretty darn common scenario that must have a clear and easy solution. So you'd think, maybe, setting the appropriate $form_state['values']
array element would do the trick? Well, no, apparently that's not what $form_state['values']
is designed for, and sure enough, it doesn't work in practice. Okay, fine. That rules out form_set_value()
, too. No problem - it does seem a bit unintuitive that form_set_value()
doesn't actually set a value in the form that will be read the next time the form is created - but that's fine, let's move on.
So, let's just set the ['#value']
of the corresponding field in the $form (also passed to the ..._submit()
function) to the value we're trying to set it to. This is based on advice by this Drupal expert at the end of his comment. Doesn't work. Maybe because $form
is not passed to ..._submit()
a reference? Okay, maybe he meant something else.
Finally, after much Googling, I come across this solution, thanks to the efforts of poor Alex, struggling with the same problem. Alex says you have to use the copy of the form provided by $form_state['complete form']
to set the ['#value']
property of the field you want to pre-populate. Doing this, as he says, in fact does allow the value to be pre-populated in my form the next time it happens.
So, if this is the correct way to do this (or is it? can anyone confirm?), then why isn't it mentioned anywhere in the Drupal 7 API? It seems like such a basic and essential part of form manipulation.
My hope is that I've missed the obvious, and that the FAPI documentation in fact does clearly explain the correct procedure for modifying the form state programmatically.
Comments
I think better use
I think better use $form_state['storage']['somefield'] and use some logic in $form['somefield']['#default_value'] to switch between $form_state['storage'] if exists or use other value taken from database if exists.
--------------------------------------------------------------------------------------------------------
if you can use drupal why use others?
VicTheme.com
submit handler vs. form builder
Changing
$form['element']['#default_value']
in the..._submit()
handler doesn't seem to have an effect anymore than changing$form['element']['#value']
does. But are you suggesting not trying to change the form in the..._submit()
handler at all, and rather do so in the form builder function? Is this the correct approach?The only way I could do that would be to run the form builder a second time, after the submit handler is run, by setting
$form_state['rebuild'] = TRUE
at the end of..._submit()
. Currently, upon submission, I have the form being rebuilt once, then the submit handler runs, and then the form is fed to the browser. It would be nice to keep the number of form rebuilds to one, as I have now.is this for a "field widget"
is this for a "field widget" or normal form?
anyway for a normal form :
you dont change the default_value in the submit handler, instead you do the logic for changing from a default value taken from database or value from form_state in the form array it self.
the submit handler only move the value from $form_state['values'] to $form_state['storage'] so when the form is rebuild / reloaded / refreshed the form array can grab the storage and decide to use the stored value or value from database.
as for field widget, this approach need further modification, the concept is to build the form state of the widget and when processed use it to set the parent form form_state.
--------------------------------------------------------------------------------------------------------
if you can use drupal why use others?
VicTheme.com
Using "#default_value" doesn't work?
This is just for a normal, simple form with regular text fields.
Well that makes sense to me, and I thought I tried that already. Okay, so I changed my code to store the new default data in
$form_state['storage']
in my submit function, then in my form building function, I check to see if any values are in storage. If they are, I set the['#default_value']
of the fields I want to fill with those values.Sadly, that doesn't work. I made sure to set
$form_state['rebuild'] = TRUE
to make sure the form builder function would be called again, and it is, and the values are properly being retrieved from storage and being assigned to['#default_value']
. I suspect Drupal is ignoring the['#default_value']
setting, however, because the form has already been created. That's how['#default_value']
is supposed to work, right? It's only supposed to provide a default value for the element when the form is first created, not after it has already been submitted. However, this form has already been submitted, perhaps multiple times, so I guess['#default_value']
is not an appropriate solution here.Any other ideas? This is why I've become so frustrated (as you might have sensed :). I'm going to have to resort back to setting the value in
$form_state['complete form']
again for now.I assume you do have
I assume you do have &$form_state in the submit and form function?
like :
if the form has $form_state['values'] then I believe ['#default_value'] is ignored and use ['#value'] instead
--------------------------------------------------------------------------------------------------------
if you can use drupal why use others?
VicTheme.com
Exact Problem?
paul2 et. al,
I wonder if I'm struggling with the exact problem here
http://drupal.org/node/1397100
I've been dealing with this for a few days now with absolutely no luck. I just can't seem to find a solution. Also, regarding default values, I noticed in the FAPI that its definition is
The value of the form element that will be displayed or selected initially if the form has not been submitted yet.
If the form was already submitted once setting 'default_value' does not work:
Thanks
Yup
My form builder and submit handler functions are defined exactly as specified in the Drupal 7 API for form generation, but that means my
$form
argument is not passed by reference.Okay. Maybe that's what I'm already doing in the submit handler by setting the
['#value']
property in the$form_state['complete form']
reference. Perhaps it's safer if I set the['#value']
in the form generation function instead.Help Understanding $form_state['complete_form']
Hi paul2,
Just wondering what you mean by
I'm not sure I understand how I can use this to pre-populate / retrieve (the values of various fields) for a previously submitted form. Any help / guidance would be greatly appreciated!
Thank you!
Clarification
Hi Vinit,
Here's a more complete example of my solution. Here's the form builder function:
The submit handler:
Thanks
paul2,
Thanks for the clarification and the example. This really helps things for me.
I had another (hopefully related) question:
So now that we have this
Is it possible to have another function that'll give the user the option to edit the same form she submitted previously (in the above function). If so, how do we pre-populate the fields with '$my_value', '$my_value2' and 'my arbitrary value'? I tried the following piece of code but it does not work.
I've tried drupal_set_messaging all three values ('$my_value', '$my_value2', 'my arbitrary value') and they print out just fine. However, I can't get them to be set in the form once it's already been submitted and I can't figure out what I'm doing wrong.
Also, sorry if this is not in line with original question. I'm really hoping it is.
Thanks very much,
Use '#value'
Yup. So let me just make sure I understand: you have values in storage, saved from some past point of the form's existence, and you want to prefill the form with those values on demand (rather than in the submit handler, like I need to do). So if you follow the conversation I've been having with @duckzland above, you'll see that I encountered the exact same problem with using '#default_value' in the form building function as you have. It doesn't work. So he responded explaining that you should be using the '#value' property instead. Try that out.
'#value' Works But...
Yes, you got that right exactly.
OK. Thank you for bringing this to my attention. This does seem to work perfectly; but not always. When I use the 'text_format' attribute, I'm unable to get the text area to show up - let alone set the value. Consider the following function
I'm wondering if this is a related problem or a new issue altogether because the text area doesn't show up in the 'edit' version of the function: 'mymodule_form_edit'. It shows up just fine in the function 'mymodule_form' (which is used to fill up the form the first time):
Any thoughts? I can't figure it out. The only thing that's changed is setting '#default_value' to '#value'.
Thanks very much for your help.
P.S:
[1] It looks similar to what 'hass' says in the beginning of this post and comment # 1
http://drupal.org/node/820816
[2] It's also similar to this thread in that the text area or the WYSIWYG editor don't load at all
http://drupal.org/node/739558
'#text_format' type is a D7 anomaly
I've also been climbing the learning curve as I try to implement a
'#text_format'
type of input element into my own form. It seems that this element type is a "special type", and unfortunately terribly documented. This element type actually stores two values: the text input by the user, and the format chosen by the user. To accommodate these two values, when the form is processed, all'#text_format'
elements have two sub-elements created for it:'value'
and'format'
. I just discovered this by myself usingerror_log(print_r(..., true))
statements in my submit handler (which you might want to be doing as well to inspect form structures, or perhaps you have another debugging solution).The text value of the field is can be found under
$form_state['values']['some_text_format_field']['value']
element. Keep in mind that with any'#text_format'
element you should be just as interested in saving the user's chosen input format, which I think can be found in$form_state['values']['some_field']['format']
.In the case of your setting
['#value']
in the form builder, I'm not sure what the correct solution is. You need to be able to assign the['#value']
element of the'value'
sub-element of the formatted text field which (I think) hasn't even been generated yet in your form builder function. Those sub-elements are probably created later by some other function.Perhaps you can follow the technique I'm using of changing values in the
'complete form'
form reference, accessed from the$form_state
array? That might work, but you may have to do this outside of your form builder function.Good luck! I've got to focus on my own list of problems now, I hope you find a solution.
$form_state['input'] and form caching
This must be the worst DX WTF I've encountered in the last couple of years. The solution I've found that seems least offensive to me is to alter the values in $form_state['input'] and force the form to not cache:
I can't help thinking that the Right Way to do this would be to alter the '#default_value' of an element in the form alter implementation, based on the value(s) of some variable(s) you tuck away in $form_state in the submit callback. This is how the node form preview button works, and anything else seems dreadfully kludgy. But although this works for adding new elements to the form, I can't find a way to make it work for elements that have already had their values set.
I use the following
I use the following method:
1) Query any data from the database. Create an object with this data
2) Call drupal_get_form() and pass it the form_definition function name, and the object you created (ex: drupal_get_form('some_form', $some_object))
3) Use this object in your form definition to set your default values
4) On submit, save the data to the database. If you have no redirects, the page will be refreshed, and the steps will be repeated from step 1.
An example I wrote with some code: http://drupal.org/node/1670656#comment-6198558
Thank you - very helpful
I must admit I wonder if I will ever get my head around the workings of drupal.
I managed to workaround this
I managed to workaround this issue by doing:
FVS - https://dmarcpal.com