I have a Zend_Form form, with some custom decorators, like this:
$decorators = array();
$decorators[] = new Zend_Form_Decorator_ViewHelper(array());
$decorators[] = new Zend_Form_Decorator_Errors;
$decorators[] = new Zend_Form_Decorator_HtmlTag(array('tag' => 'div', 'class' => 'form-item'));
$decorators[] = new Zend_Form_Decorator_Label(array('class' => 'form-label'));
$decorators[] = new Zend_Form_Decorator_Callback(array(
'callback' => function($content, $element, $options) {
return sprintf('<div class="form-row">%s</div>', $content);
},
'placement' => false
));
$this->setElementDecorators($decorators);
The problem is, that all of the fields are rendered as text inputs. Why does it happen?
EDIT: I discovered, that it doesn't render all the inputs necessarily as text inputs, but renders them with type of the first input in form. Here is example of a form that i use(the decorators are set int parent's init):
<?php
class Form_Users_Add extends Form_Base {
protected $pbxs = array(1 => 'Element 1', 2 => 'Element 2');
public function init() {
$monitors = new Zend_Form_Element_Checkbox('prefered_screen_count');
$monitors->setCheckedValue(2);
$monitors->setUncheckedValue(1);
$monitors->setLabel('two_monitors');
$this->addElement($monitors);
$pbx = new Zend_Form_Element_Select('asterisk_id');
$pbx->setMultiOptions($this->pbxs);
$pbx->setLabel('users_asterisk_id');
$this->addElement($pbx);
parent::init();
}
}
Yay! I have solved the issue! The cause was that I used INSTANCES of classes, not the names. This way every element was using the same instance of the decorator.
Related
I am trying to prepopulate a form's drop down options via data stored statically in the module.config.php in Zend 2 and am running into a problem which entails:
I try to get the Servicemanager in the __construct() function but it is unavailable.
I move the element declarations to another function within the form class so I can pass variables into it but the view controller cannot find the elements.
I currently call the form via a Servicemanager Invokable. How can I pass these arrays into the form's __construct() function?
Here is the code:
class ILLForm extends Form
{
public function __construct($fieldsetName, $campuses, $ILLTypes, $getFromOptions)
{
parent::__construct('create_ill');
$this
->setAttribute('method', 'post')
->setHydrator(new ClassMethodsHydrator(false))
->setInputFilter(new InputFilter())
;
$ill = new ILLFieldset('ill', $campuses, $ILLTypes, $getFromOptions);
$ill->setName('ill')
->setOptions(array(
'use_as_base_fieldset' => true,
));
$captcha = new Element\Captcha('captcha');
$captchaAdapter = new Captcha\Dumb();
$captchaAdapter->setWordlen(5);
$captcha->setCaptcha($captchaAdapter)
->setLabelAttributes(array('class' => 'sq-form-question-title'))
->setAttribute('class', 'sq-form-field required')
->setLabel("* Captcha")
->setAttribute('title', 'Help to prevent SPAM');
$submit = new Element\Submit('submit');
$submit->setAttribute('value', 'Submit ILL')
->setAttribute('class', 'sq-form-submit')
->setAttribute('title', 'Submit ILL');
$this->add($ill)
->add($captcha)
->add($submit);
}
}
The Indexcontroller Factory that calls the Form:
class IndexControllerFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $controllers)
{
$allServices = $controllers->getServiceLocator();
$sm = $allServices->get('ServiceManager');
$smConfig = $allServices->get('config');
$campuses = $smConfig['campuses'];
$illCategories = $smConfig['ILLCategories'];
$getFromOptions = $smConfig['getFromOptions'];
$controller = new IndexController();
$controller->setCampuses($campuses);
$controller->setILLCategories($illCategories);
$controller->setGetFromOptions($getFromOptions);
$controller->setILLForm($sm->get('ILL-form'));
$controller->setILLFormFilter($sm->get('ILL-form-filter'));
//$controller->setParams($sm->get('params'));
return $controller;
}
}
and the relevant module.config.php excerpt:
'service_manager' => array(
'abstract_factories' => array(
'Zend\Cache\Service\StorageCacheAbstractServiceFactory',
'Zend\Log\LoggerAbstractServiceFactory',
),
'invokables' => array(
'ILL-form-filter' => 'ILL\Form\ILLFormFilter',
'ILL-form' => 'ILL\Form\ILLForm',
),
I ended up taking the form out of the service manager invokables in module.config.php (removed line for 'ILL-form') and call it from the indexControllerFactory.php instead
$create_ill = new Form\ILLForm('create_ill', $campuses, $illCategories, $getFromOptions);
$controller->setILLForm($create_ill);
instead of
$controller->setILLForm($sm->get('ILL-form'));
I use an ActiveForm in Yii2 for my SearchModel. After click on search button the form fields remember previous values but SorterDropdown is refreshed.
<?php echo SorterDropdown::widget(['sort' => $dataProvider->sort,
'label' => $model->sortedBy($dataProvider->sort->attributes),])
?>
SorterDropdown is just a wrapper of ButtonDropdown.
How can I forse the SorterDropdown to remember sort order (and show it) after the form submition?
class SorterDropdown extends LinkSorter
{
public $label;
protected function renderSortLinks()
{
$attributes = empty($this->attributes) ? array_keys($this->sort->attributes) : $this->attributes;
$links = [];
foreach ($attributes as $name) {
$links[] = Html::tag('li', $this->sort->link($name, ['tabindex' => '-1']));
}
if (empty($this->label))
$this->label = 'Sort';
return \yii\bootstrap\ButtonDropdown::widget([
'encodeLabel' => false,
'label' => $this->label,
'dropdown' => [
'items' => $links,
],
]);
}
You should add some class to li element, which indicate active state of it and special style in CSS file.
I am trying to create multi import data, so I need many form collection this same class in one place. I can do this using collection type.
I created pictures Class with have one field: pictures and it is arrayCollection type like this:
class Pictures {
protected $pictures;
public function __construct()
{
$this->pictures = new \Doctrine\Common\Collections\ArrayCollection();
}
public function addPicture(Picture $picture)
{
$this->pictures[] = $picture;
return $this;
}
public function removePicture(Picture $picture)
{
$this->pictures->removeElement($picture);
}
public function getPictures()
{
return $this->pictures;
}
}
Next I created pictures form with collection to pictureType.
$builder
->add('pictures', 'collection', array(
'prototype' => false,
'by_reference' => true,
'entry_type' => PictureType::class,
'options' => array('label' => false))
)
;
Next I have picture Entity with fields for example name, width, height, image (nevermind).
So my PictureType is a simple form fith fields that same like Entity (standard).
Now I try to render this form and add some picture in controller (not from database). Then I create Picture Object and next I add it to pictures->addPicture($picture);
$pictures = new Pictures();
foreach($data as $d){
$picture = new Picture();
$picture->setName($d['title']);
$picture->setImage($d['thumbnail_400_url']);
$picture->setWidth($d['width']);
$picture->setHeight($d['height']);
$pictures->addPicture($picture);
}
$form = $this->createForm('PicturesType', $pictures, array(
'action' => $this->generateUrl('dashboard_fotolia_save'),
'method' => 'POST',
));
After it if rendered form is ok. I can see and change values.
But after submit form data disapear. I hope data will be stored in response but not:(
I want to use it only for create new object. Could you help me?
Form errors: This form should not contain extra fields
Actually it seems that your PicturesType holds a pictures field since you add it with :
$builder->add('pictures', 'collection', ...
So you got a form type with holds an array of data with a key 'pictures' for the corresponding fields.
You may want to set it by :
$form = $this->createForm('PicturesType', array('pictures' => $pictures), ...
In my form i need this:
<li class ="af_title"><div>Contact form</div></li>
I understand that if I need for example a text field - then I'd just create Zend_Form_Element_Text and wrap HtmlTag decorator around it - right?
questions:
1) how would I generate div form element so I can wrap decorator around it?
2) mmm. - how would I set content of said element to be "Contact form"?
Thanks:)
To wrap your Contact form around div which is inside <li class ="af_title"> you can do as follows:
$yourForm = new YourForm();
$yourForm->addDecorator(array('div' => 'HtmlTag'), array('tag' => 'div'));
$yourForm->addDecorator(array('li' => 'HtmlTag'), array('tag' => 'li', 'class' => 'af_title'));
EDIT:
I see that you speak of div form element. Such element does not exist, but you could easily create it. For this you need two things: new form element (i.e. div element) and a form view helper that would take care of generation of the html. I allowed myself to prepare simple examples of these two elements to show what I mean:
Div.php in APPLICATION_PATH . /forms/Element:
class My_Form_Element_Div extends Zend_Form_Element {
/**
* Default form view helper to use for rendering
* #var string
*/
public $helper = 'formDiv';
public function __construct($spec, $options = null) {
parent::__construct($spec, $options);
$this->removeDecorator('label');
$this->removeDecorator('htmlTag');
}
}
FormDiv.php in APPLICATION_PATH . /views/helpers:
class My_View_Helper_FormDiv extends Zend_View_Helper_FormElement {
public function formDiv($name, $value = null, $attribs = null) {
$class = '';
if (isset($attribs['class'])) {
$class = 'class = "'. $attribs['class'] .'"';
}
return "<li $class><div>$value</div></li>";
}
}
Having this, you can just add the div form element to any form element in their init() method as follows:
$div = new My_Form_Element_Div('mydiv');
$div->setValue('Contact form')->setAttrib('class', 'af_title');
$this->addElement($div);
Well, I have this form:
class CaracteristicaForm extends sfForm {
public function configure() {
$this->setWidgets(array(
'caracteristica' => new sfWidgetFormInputText(array('default'=>'hola mundo'))
));
$this->setValidators(array(
'caracteristica' => new sfValidatorString(
array(
'max_length' => 150,
'required' => true
)
)
));
$this->errorSchema = new sfValidatorErrorSchema($this->validatorSchema);
}
}
and then I try to...
$form = new CaracteristicaForm();
$this->embedForm('caracteristica', $form);
but the rendered inputText does not have any value at all.
What am I missing?
Ok, to reproduce this you need to embed this form into another form (mine is a Doctrine child form) so maybe is something about some method changing the value?
Well, passing an array defaults did the trick:
$form = new CaracteristicaForm(array('caracteristica' => $caracteristica));
Why not try to
$form->setDefault('caracteristica', $caracteristica);
in action?