Today's topic: I want to have part of my form hidden initially, and instead show a button saying: "toggle more questions".
So, we make it a display group (where ex1 and ex2 are the form elements to hide):
$form->addDisplayGroup(array('ex1','ex2'),'extras');
By default this wraps it in a fieldset, with no place I could see to slip in my CSS, javascript and the toggle link. What I need is a decorator, I said to myself.
Oh, gasp, does Zend make this difficult or what! In another part of this project custom decorators had been used for a minor layout change. 7 classes in 3 directories, almost all of it boilerplate. The real work was being done in CSS; those 7 classes were just to give a way to name the items as far as I could tell.
The problem is the Zend Framework Philosophy of making things complex. Did you realize there is no addDecorator($myclass) function! You have to keep decorators in a special directory and then tell Zend where to get them. Then addDecorator('part_of_my_class_name').
ZF's saving grace is that it is open source. So I poked around, and here is my solution. First, I'll define an alias for readability (optional):
$displayGroup=$form->getDisplayGroup('extras');
Remove all the default stuff I don't need (this step is optional too):
$displayGroup->removeDecorator('Fieldset'); $displayGroup->removeDecorator('HtmlTag'); $displayGroup->removeDecorator('DtDdWrapper');
Now insert my decorator (these 4 lines are in lieu of addDecorator($myclass)):
$decorators=$displayGroup->getDecorators(); $decorators['MyTest']=new MyTestDecorator(); $displayGroup->clearDecorators(); $displayGroup->addDecorators($decorators);
(I.e. get the current decorators, add mine, then replace the existing decorators with the new set.)
Finally we get to the meat. All you need is to define a render() function that takes a string (the existing content) and returns that string, optionally modified. Here is the minimal version that does nothing.
class MyTestDecorator extends Zend_Form_Decorator_Abstract { public function render($content){ return $content; } }
And here is the full version: it hides the elements in the group and uses JQuery to show/hide it. The CSS is inline.
class MyTestDecorator extends Zend_Form_Decorator_Abstract { public function render($content) { $js="$('#extra_questions').toggle();return false;"; return '<a href="" onclick="'.$js.'">Toggle Tags Visibility</a>'. '<div id="extra_questions" style="display: none;">'.$content.'</div>'; } }
Yep, it's that simple. Oooh, the architects of ZF must be turning red with rage ;-)
UPDATE: The best article I've found so far on Zend Form Decorators. As many of the comments say, the length of the article is also a very good argument against using Zend Form. And it still didn't answer my questions, so it really needed to be 2-3 times as long. But if you need to format a form, it is a far more useful resource than the utterly inadequate Zend Form manual.
2 comments:
Thanks that was very useful. I'm currently using Zend for a rather big project and I had no idea of the amount of unhappiness it was going to cause me with things like this!
A helpful article on using DisplayGroups:
http://zendgeek.blogspot.com/2009/07/zend-form-display-groups-decorators.html
Post a Comment