Using ViewScript Decorator on Nested Subforms (Zend Form)
Asked Answered
A

4

6

I want to use a view script to render my zend form as it seems to be the best way to control the layout/design of the form while still using the Zend_Elements classes.

From the view script, I render the element with $this->element->getElement('elementName') .

I'm having problems with the names of the elements. This is actually a sub-form inside a sub-form inside a form.

When I used the FormElements decorators , the fully qualified name of the elements was form[subForm][subForm][element] , which was good. Wehn I moved to the viewScript decorators, it changed to subForm[subForm][element].

I understood that I need to use the PrepareElements decorator to fix this, but this caused the name to change form[subForm][form][subForm][subForm][elements] (it doubled the first two names in the start).

Any ideas how I should handle this?

Thanks.

UPDATE: I tried to debug PrepareElements and I really don't understand what is doing. It seems like it works ok in the first iteration, but then it adds again the form[subform] prefix when running on one of the middle subforms.

When I'm not using the PrepareElements decorator, I'm just missing the "form" prefix in the names (i.e., instead of form[subForm][element], I get only subForm[element]).

May be I can just fix this somehow?

I tried to change the belongsTo but that only replaced the "subForm" prefix .

It actually seems like what is missing is a belongsTo method on the subForm.

Again, this is all because of the ViewScript decorator. It works fine with the FormElements decorators.

UPDATE 2: Just to clarify, I wouldn't mind this name change, but it causes my fields to not populate when I call form->populate .

Edit: I think that I've narrowed the problem to this: when I get my values back in setDefaults, they are ordered like this:

array(
\"formElements1-name\" => value1... \"subFormName\" => array(
\"parentFormName\" => array(
\"subFormName\" => subForm-values-array
)
)

... The main problem here is the "parentFormName" => "subFormNAme".. what does it repeat itself? I'm already in the main form. I'm guessing this is caused because I've set the setElementsBelongTo(formName[subFormName]) , but if I wouldn't do that, then I would get my subform values completely separate from the form,

i.e. values array = array( \"formName\" => array( formValues ), \"subFormNAme\" => array( subFormValues )

, while I exepct it to be

array(
formName => array(
subFormNAme => values-array
)
)...

Is it even possible to make this work?

Abnaki answered 28/9, 2011 at 21:7 Comment(3)
Exact duplicate of Zend: ViewScript decorator and array notationCrosspurpose
It's not a duplicate since I'm already using the suggested solutions but it doesn't work well.Abnaki
Zend forms has to be the most broken, ridiculous, insane piece of crap I've ever had the misfortune to be subjected to. I totally feel your pain, if you figure out what's wrong then by all means please let me know!Exterior
A
2

The current solution is to use the PrepareElements decorator on the subforms with one change - remove the recursive call in the PrepareElements code. Also, no "setElementsBelongTo" is required.

This seem to generate the correct names and ids.

Abnaki answered 4/10, 2011 at 13:15 Comment(1)
Did you modify PrepareElements.php of Zend?Farina
R
8

Are you just trying to output your form using <?php echo $this->form; ?> from your view script?

That works well for simple forms, but for my more complex forms I tend to render each element individually but don't need to use ViewScript decorator on each individual element to do this. Just try something like this from your view script:

<div class="form">
    <fieldset>
        <legend>Some Form Name</legend>
        <form action="<?php echo $this->escape($this->form->getAction()) ?>"
              method="<?php echo $this->escape($this->form->getMethod()) ?>"
              enctype="multipart/form-data">

            <?php echo $this->form->id; // render the id element here ?>

            <div class="half">
                <?php echo $this->form->name; // render the user name field here ?>
            </div>
            <div class="half">
                <?php echo $this->form->description; // render the description element here ?>
            </div>
            <div class="clear"></div>

            <div class="half">
                <?php echo $this->form->address1; // render the address ?>
            </div>
            <div class="half">
                <?php echo $this->form->address2; // render address2 ?>
            </div>
            <div class="clear"></div>

            <div class="third">
                <?php echo $this->form->zip; // render zip code ?>
            </div>
            <div class="third">
                <?php echo $this->form->city; // render city ?>
            </div>
            <div class="third">
                <?php echo $this->form->state; // render state ?>
            </div>
            <div class="clear"></div>

            <div class="half">
                <?php echo $this->form->country; // render country ?>
            </div>
            <div class="clear"></div>

            <?php echo $this->form->submit; ?>

        </form>
    </fieldset>
</div>

That is how I do most of my forms because I want to have some elements take up half the width and others the full width.

Surprisingly, the reference guide doesn't tell you that you can do this. I seem to remember a page about it in the past but cannot find it now. When I got started with Zend Framework, I thought the only way I could get my form to output exactly how I wanted was to create complex decorators, but that is not the case.

Matthew Weier O'Phinney has a great blog post on rendering Zend_Form decorators individually which explains what I did above. I hope they add this to the first page of Zend Form because that was discouraging to me at first. The fact is, 90% of my forms render elements individually instead of just echo'ing the form itself.

Note: To stop ZF from enclosing my form elements in the dt and dd tags, I apply this decorator to all of my standard form elements. I have a base form class that I extend all of my forms from so I don't have to repeat this everywhere. This is the decorator for the element so I can use tags to enclose my elements.

public $elementDecorators = array(
    'ViewHelper',
    'Errors',
    array('Description', array('tag' => 'p',    'class' => 'description')),
    array('HtmlTag',     array('tag' => 'div', 'class' => 'form-div')),
    array('Label',       array('class' => 'form-label', 'requiredSuffix' => '*'))
);

For my submit buttons I use

public $buttonDecorators = array(
    'ViewHelper',
    array('HtmlTag', array('tag' => 'div', 'class' => 'form-button'))
);
Revert answered 28/9, 2011 at 22:12 Comment(1)
This is exactly what I'm trying to do, only with sub-forms . The problem is that the generated names of the sub form elements are wrong when I use the ViewScript decorator.Abnaki
A
2

The current solution is to use the PrepareElements decorator on the subforms with one change - remove the recursive call in the PrepareElements code. Also, no "setElementsBelongTo" is required.

This seem to generate the correct names and ids.

Abnaki answered 4/10, 2011 at 13:15 Comment(1)
Did you modify PrepareElements.php of Zend?Farina
B
0

The solution would be to use the belongsTo() form element property.
Example :

new Zend_Form_Element_Text('<elementName>', array('belongsTo' => '<subformName>'))

In this way, the render() method will use a form element name like

name="<subformName>[<elementName>]"
Belsky answered 12/7, 2012 at 13:33 Comment(0)
P
0

I had the same problem and i solved it with a decorator

1 : Create a generic subform with elements

2 : Using a specific decorator with PrepareElements

3 : Change form to an array with setIsArray(true)

Example :

Form

$i = 4;
for($i = 0; $i < $nbReclam ; $i++)
{
    $rowForm = new Zend_Form_SubForm($i);
    $name= new Zend_Form_Element_Textarea('name');
    $rowForm->addElement($name);
    $this->addSubForm($rowForm, $i);
}

$this->setDecorators(array(
            'PrepareElements',
            array('ViewScript', array('viewScript' => 'myDecorator.phtml')),
    ));   


$this->setIsArray(true);

Decorator

<table>
<thead>
    <tr>
        <th>N°</th>
        <th>Name</th>
    </tr>
</thead>
<tbody>
    <?php foreach ($this->element->getSubForms() as $subForm) : ?>
            <tr>
               <td> <?php echo $i++?> </td>
               <?php foreach ($subForm->getElements() as $row) : ?>
                   <td><?php echo $row ?></td>
               <?php endforeach ?>
            </tr>
        <?php endforeach ?>
    </tbody>
</table>

Enjoy

Sorry for my english, i am french

Peremptory answered 19/5, 2014 at 13:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.