[TYPO3-mvc] Multiple Checkboxes for an object in a form

Franz Koch typo3.RemoveForMessage at elements-net.de
Tue Nov 9 15:48:10 CET 2010


Hey,

>> Of which type is your categories property?
> It is an object storage but I use the "getMailCategoriesAsArray()" and
> method in the domain model to return a key-value array (i.e. the uid is
> the key, the title the value). The "setMailCategoriesAsArray()" takes an
> array of ids and (un-)links modified objects.
> Usually this should work.(?) The unexpected behavior occurs in the form
> validation with a messed up HMAC.

Ah, ok, then yes - that could interfere with the HMAC, but it actually 
shouldn't as long as you use the viewHelpers to build the form fields.

>> Have you tried that approach by binding the checkbox to the property
>> instead?
>
> Yep. But I don't see how this should work. The only values shown are
> those that are already linked to the specific instance of the address. I
> could preselect all categories, but that is not really what I want.
> Additionally it would not be possible to subscribe to additional
> categories later on.

I think you got me wrong on this one. You traverse a custom 
viewHelperVariable containing ALL selectable categories and build the 
checkboxes for those. But those checkboxes are bound to your property

<f:for each="{allAvailableCategories}" as="category">
   <f:form.checkbox property="categories" ... />
</f:for>

But as your property is of type objectStorage it won't work for you with 
the default checkboxViewHelper. But that's what I do. This way, the 
preselection is not bound to the already related category of the 
subscription object and you can do the preselection however you like.


> Btw. I'm working with Fluid 1.2.0 and Exbase 1.2.0 - the versions
> shipped with TYPO3 4.4. I would have tried SVN trunk, but the mailing
> list states it was broken at this time.

Yepp, it's currently broken, but it should be fixed tomorrow after the 
commit of the dispatcher refactoring.

>> Of course. Just yesterday I created a form where visitors can order
>> brochures and the selection is done via checkboxes (my custom
>> checkboxViewHelper allowing objectStorages though). For me your code
>> is working just fine, the only difference I have is that I bound the
>> checkbox to the property.
> I guess you did that by preselecting all brochures..?

No. As mentioned above, I fetched all selectable brochures from the 
repository and assigned them to the view. Then I itterate over them and 
create checkboxes bound to my object property.



My custom checkboxViewHelper looks like this:
--------------
> class Tx_ElementsExtbase_ViewHelpers_Form_CheckboxViewHelper extends Tx_Fluid_ViewHelpers_Form_CheckboxViewHelper {
>
> 	/**
> 	 * Renders the checkbox.
> 	 *
> 	 * @param boolean $checked Specifies that the input element should be preselected
> 	 *
> 	 * @return string
> 	 * @author Bastian Waidelich <###>
> 	 * @author Franz Koch <###>
> 	 * @api
> 	 */
> 	public function render($checked = NULL) {
> 		$this->tag->addAttribute('type', 'checkbox');
>
> 		$nameAttribute = $this->getName();
> 		$valueAttribute = $this->getValue();
> 		if ($checked === NULL && $this->isObjectAccessorMode() && $this->viewHelperVariableContainer->exists('Tx_Fluid_ViewHelpers_FormViewHelper', 'formObject')) {
> 			$propertyValue = $this->getPropertyValue();
> 			if (is_bool($propertyValue)) {
> 				$checked = $propertyValue === (boolean)$valueAttribute;
> 			} else if ($propertyValue === NULL) {
> 				$checked = FALSE;
> 			} elseif (is_array($propertyValue) || $propertyValue instanceof Traversable) {
> 				if (method_exists($propertyValue, 'toArray')) {
> 					$propertyValue = $propertyValue->toArray();
> 				}
>
> 				if (gettype(current($propertyValue)) == 'object') {
> 					foreach($propertyValue as $object) {
> 						if (method_exists($object,'getUid') && $object->getUid() == $valueAttribute) {
> 							$checked = TRUE;
> 							break;
> 						} else if ($object->__toString() == $valueAttribute) {
> 							$checked = TRUE;
> 							break;
> 						}
> 					}
> 				} else {
> 					$checked = in_array($valueAttribute, $propertyValue);
> 				}
> 				$nameAttribute .= '[]';
> 			} else {
> 				throw new Tx_Fluid_Core_ViewHelper_Exception('Checkbox viewhelpers can only be bound to properties of type boolean or array. Property "' . $this->arguments['property'] . '" is of type "' . (is_object($propertyValue) ? get_class($propertyValue) : gettype($propertyValue)) . '".' , 1248261038);
> 			}
> 		}
>
> 		$this->registerFieldNameForFormTokenGeneration($nameAttribute);
> 		$this->tag->addAttribute('name', $nameAttribute);
> 		$this->tag->addAttribute('value', $valueAttribute);
> 		if ($checked) {
> 			$this->tag->addAttribute('checked', 'checked');
> 		}
>
> 		$this->setErrorClassAttribute();
>
> 		$hiddenField = $this->renderHiddenFieldForEmptyValue();
> 		return $hiddenField . $this->tag->render();
> 	}
> }
--------------

-- 
kind regards,
Franz Koch


More information about the TYPO3-project-typo3v4mvc mailing list