How to set a class attribute to a Symfony2 form input - php

How can I set the HTML class attribute to a form <input> using the FormBuilder in Symfony2 ?
Something like this:
->add('birthdate', 'date',array(
'input' => 'datetime',
'widget' => 'single_text',
'attr' => array(
'class' => 'calendar'
)
))
{{ form_widget(form.birthdate) }}
I want this inputfield with the attribute class set to calendar

You can do this from the twig template:
{{ form_widget(form.birthdate, { 'attr': {'class': 'calendar'} }) }}
From http://symfony.com/doc/current/book/forms.html#rendering-each-field-by-hand

You can do it with FormBuilder. Add this to the array in your FormBuilder:
'attr'=> array('class'=>'span2')

The answer by Acyra lead the right way if you want to set attributes inside the controller, but has many inaccuracies.
Yes, you can do it directly with the FormBuilder by using the attr attribute (introduced here for the 2.1 version and here for the 2.0) to the array of options as follows:
->add('birthdate', 'date',array(
'input' => 'datetime',
'widget' => 'single_text',
'attr' => array('class'=>'calendar')
))
It is not true that the "functionality is broken". It works very well!
It is not true that Symfony2 applies the HTML class attribute to both the label and the input (at least from the 2.1 version).
Moreover, since the attr attribute is an array itself, you can pass any HTML attribute you want to render for the field. It is very helpful if you wanna pass the HTML5 data- attributes.

You can add it in the options of your form class:
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\MyEntity',
'attr' => array(
'class' => 'form-horizontal'
)
));
}

{{ form_widget(form.content, { 'attr': {'class': 'tinyMCE', 'data-theme': 'advanced'} }) }}

Like this:
{{ form_widget(form.description, { 'attr': {'class': 'form-control', 'rows': '5', 'style': 'resize:none;'} }) }}

You can to this in Twig or the FormClass as shown in the examples above. But you might want to decide in the controller which class your form should get. Just keep in mind to not have much logic in the controller in general!
$form = $this->createForm(ContactForm::class, null, [
'attr' => [
'class' => 'my_contact_form'
]
]);

Renders the HTML widget of a given field. If you apply this to an entire form or collection of fields, each underlying form row will be rendered.
{# render a field row, but display a label with text "foo" #}
{{ form_row(form.name, {'label': 'foo'}) }}
The second argument to form_row() is an array of variables. The templates provided in Symfony only allow to override the label as shown in the example above.
See "More about Form Variables" to learn about the variables argument.

Related

Symfony Form - form type options inside form class or Twig functions?

It's a little hard to specify it in the title so I'm going to give a specific example.
I created form class called FlashcardType in which I have buildForm() method and following code inside
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('exampleSentence', CheckboxType::class, [
'label' => 'Example sentence'
])
->add('pronunciation', CheckboxType::class, [
'label' => 'Pronunciation'
])
->add('sortBy', ChoiceType::class, [
'label' => 'Sort by',
'choices' => [
'Date increase' => 1,
'Date decrease' => 2,
'Word alphabetically' => 3,
'Word not alphabetically' => 4
]
])
->add('save', SubmitType::class, [
'label' => 'Submit'
]);
}
So the result form will contain 2 checkboxes, one select drop-down and submit button.
Inside the controller I pass this form to view by createView() method.
And to make this question shorter let's take only this first checkbox as example.
So inside Twig file I have the code as follows:
{# ...form code... #}
<div class="form-check form-check-inline mr-4">
{{ form_widget(form.exampleSentence, {'attr': {'class': 'form-check-input'}}) }}
{{ form_label(form.exampleSentence, null, {
'label_attr': {'class': 'form-check-label'}
}) }}
</div>
{# ...form code... #}
For checkbox type (and not only) we can set options outputted in the table while creating form by formBuilder(). But many of these options we can override in Twig functions.
For this first checkbox I set label inside buildForm() but I can also set it inside {{ form_label() }} Twig function. And I can make it for many (if not for every) option and types.
So what's the difference between wrtiting options inside form builder and Twig form functions? Which of these options should we write inside builder and which of these inside Twig? Are there some good practices in this case?
Thank you in advance for all answers!

Symfony not Render CollectionType

I create a form for a collection type of data in a separated from my controller
its my controller
/**
* #Security("has_role('ROLE_USER')")
* #Route("/phonebook/add", name="add")
*/
public function addPerson()
{
$person = new PhoneBookP();
$form = $this->createForm(PersoanlBookType::class, $person);
return $this->render(
'default/add.html.twig',
array('form' => $form->createView())
);
}
and its my form
->add('emails', CollectionType::class, array(
'entry_type' => EmailType::class,
'allow_add' => true,
'prototype' => true,
'allow_delete' => true,
'attr' => [
'class' => "emails-collection",
],
))
and my twig is
{% block body %}
{{ form(form) }}
{% endblock %}
it has no error and work in any common field (like NumberType,..) but not render CollectionType in my output. I using Symfony 4. whats my wrong?
in your rendering form you need to do this:
$person = new PhoneBookP();
//addEmail() is the arraycollection in your PhoneBookP Entity
//to be able to load the form, you need to add one from your arraycollection
$person->addEmail(new Email());
$form = $this->createForm(PersoanlBookType::class, $person);
The tags form_start and form_end only render the <form>-tags. To render the rest of the form elements call the form-twig-helper inside the <form>-tags too:
{{ form_start(form) }}
{{form(form)}}
<button type="submit">Register!</button>
{{ form_end(form) }}

Render input before label with Twig or form builder

I'm using materialize for the front end and I have an issue with the rendering of checkbox, to make the materialize checkbox works I've to put the label after the input but I build the form with symfony so this puts the label before the input. Here is how I build my form :
$builder
->add('libelle')
->add('ordre')
->add('categorie')
->add('type', ChoiceType::class, array(
'choices' => array(
'Commande' => 'commande',
'Produit' => 'produit',
'Face' => 'face',
'Job' => 'job'
)
))
->add('fin', CheckboxType::class, array(
'label' => 'Fin action'
));
And I render the form like this :
{{ form_start(edit_form, {'attr': {'class': 'full'}}) }}
{{ form_widget(edit_form) }}
{{ form_end(edit_form) }}
Is there a way with the form builder or twig to render the label after the input ?
You can output label and field separately in Twig:
{{ form_label(field_name) }}
{{ form_widget(field_name) }}

Symfony3: Proper way of persisting multiple objects from the same form

I have a Field class and a FieldType class associated to it and I want to create a interface where the user can edit the FieldType of all the Fields at once.
So I did the following:
protected function createUpdateForm() {
$fieldList = $this->getDoctrine()->getRepository('AppBundle:Field')->findAll();
$fieldTypeList = $this->getDoctrine()->getRepository('AppBundle:FieldType')->findAll();
$form = $this->createFormBuilder();
foreach ($fieldList as $field){
$form->add($field->getDescription(), ChoiceType::class,
['choices' => $fieldTypeList,
'choice_label' => 'getDescription',
'multiple'=>false, 'expanded'=>true,
'data' => $field->getFieldType()]);
}
$form->add('action', SubmitType::class, ['label' => 'Update']);
$form->add('cancel', SubmitType::class, ['label' => 'Cancel']);
return $form->getForm();
}
It takes all the Fields from the database and creates a Radio group with the FieldTypes as the image shows (just the end of the form):
So for each Field the user can select the type and update the values.
This is how I am updating the form, and that is what I do not like:
foreach ($form->getData() as $fieldType){
$field = array_shift($fieldList);
$field->setFieldType($fieldType);
$em = $this->getDoctrine()->getManager();
$em->flush();
}
It works, but everything look like a bodge, I do not like this. I'm starting with Symfony so I'm not sure, but there should be a better way to create the kind of form I need and persist it. I was trying to create a ColletionType, but it is not working out.
Does anybody know a better way to do this?
I have a more complex case that will use a similar logic so I'm trying to figure this out.
Not sure if I understood you completely, but if I did, this calls for an CollectionType as far as I can see it. Plus, if you set the underlying type to be EntityType you simplify the things even more.
I think something like this should work:
$fieldList = $this->getDoctrine()->getRepository('AppBundle:Field')->findAll();
$form = $this->createFormBuilder(['fields' => $fieldList])
->add('fields', CollectionType::class, [
'entry_type' => EntityType::class,
'entry_options' => [
'class' => 'AppBundle:FieldType',
'expanded' => true,
'choice_label' => 'description'
]
])
->add('action', SubmitType::class, ['label' => 'Update'])
->add('cancel', SubmitType::class, ['label' => 'Cancel'])
->getForm();
Update:
{{ form_label(form.fields) }}
{% for f in form.fields %}
{{ form_row(f, {'label': f.vars.value.description}) }}
{% endfor %}
Just bare in mind that I currently don't have dev env which I could use to check for typos, but it should work :)
Hope this helps a bit...

Symfony2, How to make a form label class/attr different than its input?

I would like to build a form with label and inputs, but the class of them should be different. Code below creates the label for the input with same attr:
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('hours', null ,
array('attr'=>
array(
'placeholder'=>'Working Hours',
'class'=>'ui-spinner-box') ) )
}
In my code above the ui-spinner-box will be outputted for both label and input. It will even put placeholder for its label.
So how to make it create attr for label separately so I can output something like below :
<label class="MYCLASSFOR_LABEL" for="input_id">Hours</label>
<input class="MYCLASSFOR_INPUTS" type="text" id="input_id" name="" value="" >
As mentioned in the documentation:
attr : A key-value array that will be rendered as HTML attributes on the field
label_attr: A key-value array that will be rendered as HTML attributes on the label
You can set those attributes in twig template or in form builder:
Twig template:
for symfony 2.1 and newer use:
{{ form_label(form.hours, null, {'label_attr': {'class': 'foo'}}) }}
in the legacy symfony 2.0 it used to be
{{ form_label(form.hours, { 'label_attr': {'class': 'MYCLASSFOR_LABEL'} }) }}
{{ form_widget(form.hours, { 'attr': {'class': 'MYCLASSFOR_INPUTS'} }) }}
Form builder
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('hours', null, array(
'label_attr' => array('class' => 'MYCLASSFOR_LABEL'),
'attr' => array('class' => 'MYCLASSFOR_INPUTS'),
));
}
This may be new, but there's an easy way to do this now:
$builder
->add('hours', null , array(
'attr'=>
array(
'placeholder'=>'Working Hours',
'class'=>'MYCLASSFOR_INPUTS')
) ,
'label_attr' => array(
'class' => 'MYCLASSFOR_LABEL'
)
);
The option you're looking for is label_attr.
This works for me in Symfony 2.3:
{{ form_row(form.hours, { 'label': 'Hours:'
,'label_attr': {'class': 'MYCLASSFOR_LABEL'}
,'attr': {'class': 'MYCLASSFOR_INPUTS'}
}
)
}}
The above is no longer correct, at least in the context I was using it. In Symfony 2.1 the solution is:
{{ form_label(form.item, label|default(null), { 'label_attr': { 'class': 'MYCLASS' } }) }}

Categories