Here is a short snippet from my class extending Zend_Form:
$this->addElements(array(
$inputField1,
$inputField2,
$inputField3,
$submitButton
));
$this->addDisplayGroup(array('inputField1',
'inputField2',
'inputField3',
'submitButton'),
'fieldset1',
array('legend' => 'Lorem Ipsum'));
The problem is when I print the form, it prints only the submit button, the fieldset with input fields (those are ordinary Zend_Form_Element_Text elements) isn't there.
EDIT: If I remove the $this->addDisplayGroup() (or comment it), the text elements are displayed without a problem.
Sounds like you aren't using the getDisplayGroup() in your controller or later on in the form init() method
Related
i have two embeded forms Form1 and Form2 in a general form class FormA,
in the general class, besides the embeded forms i have a choice widget and in the doBind i try to unset one of the embeded forms (depending on the choice widget content)
this does'nt WORK :
Person and animal models inherit from creature(column agregation)
protected function doBind(array $values)
{
//embeded forms are 'person' and 'animal'
$forms = $this->embeddedForms;
if($values['type']== 'animal')
{
unset($forms['person']);
unset($values['person']['last_name'], $values['person']['first_name'] , $values['person']['civility'], $values['person']['id'] );
}
parent::doBind($values);
}
the form is never unseted and in the db i have 3 saves (one for animal, one for the person and one for the creature)
any idea guys???
Unsetting an embedded form after the configure() method is called is too late in the lifecycle of a form.
Implement your configure() method so it only embeds those subforms you realy need.
For example pass the value of the selected choice to the form and then decide in the configure() method whether to add the PersonForm or the AnimalForm.
I need to create a form where the elements (texbox, select, ..) will be dynamically inserted. Right now I have created a empty Form file with just a hidden element and them in my controller I go inserting elements according to certain conditions.
My form file:
class Form_Questions extends Zend_Form {
public function __construct() {
parent::__construct($options);
$this->setName('Questions');
// Hidden Label for error output
$hiddenlabel = new Zend_Form_Element_Hidden('hiddenlabel');
$hiddenlabel->addDecorator(new Form_Decorator_HiddenLabel());
$this->addElements( array($hiddenlabel) );
}
}
In the controller I have something like:
...
$form = new Form_Questions();
$request = $this->getRequest();
if ($request->isPost())
{
$formData = $request->getPost();
if ($form->isValid($request->getPost()))
{
die(var_dump($form->getValues()));
}
}
else
{
//... add textbox, checkbox, ...
// add final submit button
$btn_submit = new Zend_Form_Element_Submit('submit');
$btn_submit->setAttrib('id', 'submitbutton');
$form->addElement($btn_submit);
$this->view->form = $form;
}
The form displays fine but the validation is giving me big trouble. My var_dump() only shows the hidden element that is staticly defined in the Form file. It does not save the dinamic elements so altought I can get them reading what's coming via POST, I can not do something like
$form->getValue('question1');
It behaves like if Zend uses the Form file to store the values when the submit happend, but since the elements are created dinamically they do not persist (either their values) after the post so I can not process them using the standar getValue() way.
I would appreciate any ideas on how to make them "live" til after the post so I can read them as in a normal form.
The form which you are calling isValid() and getValues() methods on is actually your "empty" form - you have instantiated it only a few lines up and haven't added any elements to it at that point.
Remember that POST only sends an array of fieldName => fieldValue type, it doesn't actually send a Zend_Form object.
It is difficult to suggest a new solution without knowing what you are trying to achieve. It is generally better to add all possible elements to your Zend_Form right away, and then only use the ones you need in the view scripts, i.e. echo $this->form->myField;. This will allow isValid() to process all the elements of the form.
It sounds like the form is dynamic in the sense that the questions come from a db, not in then sense that the user modifies the form itself to add new questions.
Assuming this is the case, then I wouldn't add the question fields in the controller. Rather, I'd pass the questions to the form in the constructor and then add the question fields and the validators in the form's init() method. Then in the controller, just standard isPost() and isValid() processing after that.
Or, if you are saying that the questions to be added to the form are somehow a consequence of the hidden label posted, then perhaps you need two forms and two actions: one for the hidden field form and another for the questions.
Ok, the simplest solution I came up with - to my case and considering the really of the code I am currently playing with was to load all the questions I need from the database using a method from my Model (something like fetchQuestions()), them in my controller I go throught the recordset and create the form elements according to the current question of the recordset.
The elements are stacked in an array that is passed to my Form constructor. In the form constructor I read the array and generate all the dynamic elements. I them just echoed the form to the view.
I have not seem why it would be a bad idea to override the Form constructor as I also could not use any of the set/get methods to pass this to my form.
I have a module that builds a form that includes a fieldset. Instead of using the <legend> element to render the fieldset title, I want to place this content in a <div> element instead. But I want to change the behavior only for the form returned by my module, so I don't want to place any new functionality into my theme's template.php file.
In mymod.module I have defined:
// custom rendering function for fieldset elements
function theme_mymod_fieldset($element) {
return 'test';
}
// implement hook_theme
function mymod_theme() {
return array(
'mymod_fieldset' => array('arguments' => array('element' => NULL)),
'mymod_form' => array('arguments' => array())
);
}
// return a form that is based on the 'Basic Account Info' category of the user profile
function mymod_form() {
// load the user's profile
global $user;
$account = user_load($user->uid);
// load the profile form, and then edit it
$form_state = array();
$form = drupal_retrieve_form('user_profile_form', $form_state, $account, 'Basic Account Info');
// set the custom #theme function for this fieldset
$form['Basic Account Info']['#theme'] = 'mymod_fieldset';
// more form manipulations
// ...
return $form;
}
When my page gets rendered, I expected to see the fieldset representing 'Basic Account Info' to be wholly replaced by my test message 'test'. Instead what happens is that the <fieldset> and <legend> elements are rendered as normal, but with the body of the fieldset replaced by the test message instead, like this:
<fieldset>
<legend>Basic Account Info</legend>
test
</fieldset>
Why doesn't my #theme function have the chance to replace the entire <fieldset> element? If I wrap a textfield in this function instead, I am able to completely replace the <input> element along with its label. Furthermore, if I provide an override in my site's template.php for theme_fieldset, it works as expected and I am able to completely replace the <fieldset>, so I know it is possible.
What's different about providing #theme functions to fieldsets inside a module?
Have you tried overriding theme_fieldset() instead of using the #theme function? I believe you could do something like this in your .module file:
function mymodule_fieldset($element) {
// do something;
return $html;
}
This would apply to all fieldsets. You could do some kind of check on $element for the fieldsets you want to affect and then use the default implementation for all others.
Take a look at: http://api.drupal.org/api/function/theme_fieldset/6
I know this is an old post -- but I've run into the same issue. I came up with an ugly work around. This is definitely a bug in the Form API. Maybe my temporary fix will be helpful to someone.
I found (and appended) a bug report here: http://drupal.org/node/225698
Worth checking that before trying my hacky fix.
I'm not sure what the children are in $form['Basic Account Info'] in this example, but basically what you can do is use drupal_render() on that fieldset's children, and then recreate a fieldset array separate from $form['Basic Account Info'], theme it with theme() and pass it back to the form array as markup..
$fieldsetElement = array(
//$child is the key of whatever child you need in the fieldset
//you may have to alter this for multiple children, stringing
//together multiple drupal_render calls on each children
//(#children needs to be a string.. unless your theme can handle the array)
'#children'=>drupal_render($form['Basic Account Info'][$child]),
'#attributes'=>array(),//set real attributes
'#title'=>$form['Basic Account Info']['#title']
);
$form['Basic Account Info'] = array(
'#type'=>'markup',//not really needed, is default
'#value'=>theme('mymod_fieldset',$fieldsetElement)
);
super-duper hacking, likely causes disconnect with form state and potential validation failure -- but both are fixable by trial and error with the form api. I wouldn't recommend this unless you really want to get your hands dirty with PHP and drupal form API, but that's really the only way, unless you can live without variable fieldset themes in your module... Maybe try prefix and suffix?
This is just off the top of my head but maybe the difference is because a fieldset is not a form element but just a seperator or a grouper, if you will. Maybe the #theme callback is only for form elements?
The concept of your code works, meaning you can do what you want to do.
There are some things that can explain why it doesn't work.
The fieldset is not $form['Basic Account Info'].
Need to clear cache.
$form['Basic Account Info']['#theme'] is lost/overridden later in the code execution.
Try to take a look at $form before you do any of the moderations. When I tried to copy your code I run into a bug:
user.pages.inc file needed to be loaded
I was having the same issue.
You need to use #theme_wrappers instead of #theme
'#type' => 'fieldset',
'#theme_wrappers' => array('mymodule_fieldset'),
I can add an element to a form like this:
$form->addElement($element);
However, that will put the element at the end of the form, I would like to prepend an element (put it at the beginning of the form).
Why? The form has dynamically generated fields (number of text fields and their labels are generated based on parameters from request) so the form class looks like this:
class Form1 extends Zend_Form
{
public function init()
{
$this->setMethod('post');
$submit = new Zend_Form_Element_Submit('submit1', array(
'label' => 'Submit',
'class' => 'input-submit'
));
$this->addElements(array(
$submit
));
}
}
There is only the submit button because I don't know how many text fields and with what labels there will be yet.
From the ZF manual on Zend_Form Metadata and Attributes
Zend_Form_Element handles a variety of attributes and element metadata. Basic attributes include:
order: the index at which an element should appear in the form. Uses the setOrder() and getOrder() accessors.
So you would set the button to a very high order number, e.g. 1000 and then add the dynamic elements starting with an order number of 1 (or any number lower than the button's order number).
However, when there is nothing but the button in the form at all, then why not just create the entire form on the fly and append the submit button once you are done attaching the elements from the request.
I'm having difficulty configuring Zend_Form. I have a Zend_Form sub-class. The form has some required information and some additional information. I want the additional information to be accessible via an array. The submitted data will look something like this:
$formData['required1']
$formData['required2']
$formData['addiotnalData']['aData1']
$formData['addiotnalData']['aData2']
I've Googled this and tried all the suggestions I've found (using subForms and setting the Zend_Form::setIsArray($flag) and Zend_Form::setElementsBelongTo($array) methods), but have not figured out how to do this.
What am I doing wrong? How do I set the names of form elements so that I can access the data with array notation?
Sorted it! The problem is a custom decorator that was being used.
//In
$subForm = new Form_SubForm(); //this can be a Zend_Form or Zend_Form_SubForm
$subForm->setIsArray(true);
$this->addSubForm($subForm, 'subform');
Elements will be rendered with a id of subform-elementname and a name of subform[elementname].
To expand on the answer because $form->setIsArray(TRUE) was not working with my custom decorator for elements. My custom ViewScript decorator was needed for rendering the Zend_Form_Element.
The problem, it was rendering the element name with $this->element->getName(). I had to use $this->element->getFullyQualifiedName() in the ViewScript decorator script.