Skip to content

Instantly share code, notes, and snippets.

@bakura10
Created June 30, 2012 20:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bakura10/3025309 to your computer and use it in GitHub Desktop.
Save bakura10/3025309 to your computer and use it in GitHub Desktop.
Form collection
The simplest case allow to have the same element, multiple time. For instance, let's say we want to have two colors :
$element = new \Zend\Form\Element\Color();
$this->add(array(
'type' => 'Zend\Form\Element\Collection',
'name' => 'colors',
'attributes' => array(
'count' => 2,
'targetElement' => $element
)
));
And display them using the view helper :
<?php echo $this->formCollection($form->get('colors')); ?>
This will generate the following HTML (internally it used my Form Row helper - that just have been pushed - so it take care of displaying the errors too).
<input type="color" name="colors[0]">
<input type="color" name="colors[1]">
You can add a label, so that the collection will be wrapped around a field set :
$element = new \Zend\Form\Element\Color();
$this->add(array(
'type' => 'Zend\Form\Element\Collection',
'name' => 'colors',
'label' => 'Choose colors',
'attributes' => array(
'count' => 2,
'targetElement' => $element
)
));
Of course, you can have label at a "collection level" (the field set) but also at an element level by adding label to the element.
By default, the collection element allows to add element dynamically (using JavaScript for instance), this means that new elements will also be validated and can be retrieved the same way as with normal form.
To disable this functionality, you just need to pass the option allowAdd to false :
$element = new \Zend\Form\Element\Color();
$this->add(array(
'type' => 'Zend\Form\Element\Collection',
'name' => 'colors',
'label' => 'Choose colors',
'attributes' => array(
'count' => 2,
'allowAdd' => false,
'targetElement' => $element
)
));
With this setting, dynamically added elements will be ignored. When set to true, there's an additional option that can help you to add new elements. You just need to set shouldCreateTemplate to true :
$element = new \Zend\Form\Element\Color();
$this->add(array(
'type' => 'Zend\Form\Element\Collection',
'name' => 'colors',
'attributes' => array(
'count' => 2,
'shouldCreateTemplate' => true,
'targetElement' => $element
)
));
This will generate the following HTML :
<input type="color" name="colors[0]">
<input type="color" name="colors[1]">
<div data-template="<input type="color" name="colors[__index__]"></div> <=== Normally the HTML is escaped, but I write it normally here
As you can see, the shouldCreateTemplate added a new div that contains the markup to copy in the data-template attribute. The only thing to be changed is the __index__ attribute (it's quite simple to do with jQuery).
My Collection element also works with field set (and collection can themselves contain field set that contains other collections).
For instance :
$element = new \Application\Form\AddressFieldset();
$this->add(array(
'type' => 'Zend\Form\Element\Collection',
'name' => 'addresses',
'attributes' => array(
'label' => 'Your addresses',
'count' => 2,
'shouldCreateTemplate' => true,
'targetElement' => $element
)
));
Where AddressFieldset contains the following input fields :
$this->setAttribute('label', 'One city');
$this->add(array(
'name' => 'city',
'attributes' => array(
'type' => 'text',
'label' => 'City'
)
));
$this->add(array(
'name' => 'zipCode',
'attributes' => array(
'type' => 'text',
'label' => 'ZipCode'
)
));
Once again, the whole collection is displayed like this :
<?php echo $this->formCollection($form->get('addresses')); ?>
The following HTML is displayed :
<fieldset>
<legend>Your addresses</legend>
<fieldset>
<legend>
One city
</legend>
<label>
City<input name="addresses[0][city]" type="text">
</label>
<label>
ZipCode<input name="addresses[0][zipCode]" type="text">
</label>
</fieldset>
<fieldset>
<legend>
One city
</legend>
<label>
City<input name="addresses[1][city]" type="text">
</label>
<label>
ZipCode<input name="addresses[1][zipCode]" type="text">
</label>
<div
data-template="<fieldset><legend>One city</legend><label>City<input name="addresses[__index__][city]" type="text"></label><label>ZipCode<input name="addresses[__index__][zipCode]" type="text"></label></fieldset>">
</div>
</fieldset>
As you can see, once again, to add a new element, it's just a matter of counting the number of elements, copying the data-template and replacing the __index__ placeholder by count + 1, and here you go, you can validate everything ;-).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment