How include an attribute 'class' rendering a form - symfony

I have a contact form and I'm trying to put a class to an input of my form.
This is in the ContactType:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', TextType::class);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Contact::class,
]);
}
And this in my twig:
{{ form_start(form) }}
{{ form_widget(form.name, {attr: {class: 'myclass', placeholder: 'name'} }) }}
{{ form_end(form) }}
I get this html:
<input type="text" class="form-control" id="contact_name" name="contact[name]" required="required" placeholder="name">
It's working for placeholder, but not to class. I have tried to put the attr in the builder and it is the same. Is the class form-control overwriting my class? How can I fix it?

I think you're using a bootstrap form theme, check into the config file.
and if the case, you can add this line on the top of your twig file :
{% form_theme form 'form_div_layout.html.twig' %}

Try this if it will help you
{{ form_start(form) }}
{{ form_widget(form.name, {'attr': {'class': 'input-text input-text--white', 'placeholder': 'name'} }) }}
{{ form_end(form) }}

I believe you can't define two attributes on form_wdiget. The way around this is doing both in the FormBuilder or one in the FormBuilder.
You can define attributes on a form element like so:
$builder
->add('name', TextType::class, [
'attr' => [
'class' => 'my-class',
],
]);
Note that for a CSS class, it must be in the array attr, not to be confused with a class as in your entity like on the EntityType::class.
Or
$builder
->add('name', TextType::class, [
'placeholder' => 'My place holder',
]);
So you could achieve both like:
$builder
->add('name', TextType::class, [
'attr' => [
'class' => 'my-class',
],
'placeholder' => 'My place holder',
]);
You can read more about form field attributes here.

You can read it from the official page:
https://symfony.com/doc/current/reference/forms/types/form.html#attr
Just add: {'attr': {'attribute name': 'value'}}
As shown below
{{ form_widget(form.propertyName, {'attr': {'placeholder': 'name'} }) }}

Related

Symfony - Form with multiple entity objects

I'm running Symfony 3.4 LTS and I have an entity Attribute:
<?php
class Attribute
{
private $id;
private $code;
private $value;
private $active;
// My getters and setters
Below the database table:
I would like to get, in a form, all the rows with code == 'productstatus'. I tried:
<?php
$attributes = $this->getDoctrine()->getRepository(Attribute::class)->findBy(['code' => 'productstatus']);
// $attributes contains array with 3 objects 'Attribute'
$form = $this->createFormBuilder($attributes);
$form->add('value', TextType::class);
$output = $form->getForm()->createView();
If I dump() the $output var in Twig:
... I'm unable to make a loop to display the 3 fields with values.
{{ form_start(form) }}
{{ form_widget(form) }}
{{ form_end(form) }}
Result :
My goal is to allow the user to edit all the values of a specific attributes in the same form (or multiple forms, but in the same page). I already tried with CollectionType without success.
I found a solution: create 2 nested forms and use CollectionType. Hope it helps.
<?php
// Controller
$attributes = $this->getDoctrine()->getRepository(Attribute::class)->findBy(['code' => 'productstatus']);
$form = $this->createForm(AttributeForm::class, ['attributes' => $attributes]);
// AttributeForm
$builder
->add('attributes', CollectionType::class, [
'entry_type' => AttributeValueForm::class,
'allow_add' => true,
'by_reference' => false,
'allow_delete' => true,
]);
// AttributeValueForm
$builder
->add('value', TextType::class, ['label' => false, 'required' => false])
->add('active', CheckboxType::class, ['label' => false, 'required' => false])
// Twig view
{{ form_start(form) }}
{% for attribute in form.attributes.children %}
<tr>
<td>{{ form_widget(attribute.value) }}</td>
<td>{{ form_widget(attribute.active) }}</td>
</tr>
{% endfor %}
{{ form_end(form) }}
You an use an if statement in the your AttributeType like in the example below:
$builder
->add('entree', EntityType::class, array('class'=>'cantineBundle:plat',
'choice_label'=>function($plat){
if($plat->getType()=='Entree'&&$plat->getStatus()=="non reserve"){
return $plat->getNomPlat();
}
},
'multiple'=>false)
);

How to get the changed entities only, after a submit?

I have a collection of forms like in the code below, which leads to a form that looks like the following (with two example entries):
When clicking submit, the data i provided to the form (builder) instance is updated accordingly.
Problem: The problem i have is, that the list can be quite long, so i need a way of knowing which instances have been updated.
I thought about storing a clone of the original data (here $leadPartnerList in my session. But that does not feel right.
Does symfony (specifically form builder) provide such functionality out of the box? Or what would be an efficient solution to know which fields in the form have been updated and which not?
My Twig:
{% block content %}
<div>
{{ form_start(form) }}
{% for partner in lead_partners %}
{{ form_row(partner.name) }}
{% endfor %}
{{ form_end(form) }}
</div>
{% endblock content %}
My Controller Code:
public function overview(Request $request, \App\Utility\LeadPartnerLoader $LeadPartnerLoader)
{
$leadPartnerList = $leadPartnerLoader->loadAll();
$formBuilderData = [
'lead_partners' => $leadPartnerList
];
$listForm = $formFactory->createNamedBuilder('listForm', FormType::class, $formBuilderData)
->add('lead_partners', CollectionType::class, [
'entry_type' => LeadPartnerFormType::class,
'allow_add' => true
])
->add('submit', SubmitType::class, [
'label' => 'Submit Changes'
])
->getForm();
... handleRequest and so on and so forth...
}
And the Form Type (LeadPartnerFormType):
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => LeadPartner::class,
));
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', TextType::class);
}
$leadPartnerList is of type array with LeadPartner instances within each entry of the array.
PLEASE NOTE: I'm not using Doctrine here!
Use symfony EventListener or EventSubscriber. See: https://symfony.com/doc/current/doctrine/event_listeners_subscribers.html

Getting the string of the chosen option in a drop down that comes from an entity repository

I am trying to pull in a repository into a form in Symfony 3.4 and then use the chosen option when the form is submitted.
Here's the form code:
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('text', TextareaType::class, [
'label' => 'Text'
])
->add('category', EntityType::class, [
'class' => Category::class,
'choice_label' => 'name',
'query_builder' => function(CategoryRepository $repo) {
return $repo->createQueryBuilder('c')
->groupBy('c.name');
}
])
->add('subcategory', EntityType::class, [
'class' => Category::class,
'choice_label' => 'subcategory',
'query_builder' => function(CategoryRepository $repo) {
return $repo->createQueryBuilder('c')
->groupBy('c.subcategory');
}
]);
}
With this I can render the form and it looks good. I can choose the various options in the CategoryRepository.
{% block body %}
{{ form_start(form) }}
{{ form_label(form.name) }}
{{ form_errors(form.name) }}
{{ form_widget(form.name) }}
{{ form_label(form.subcategory) }}
{{ form_errors(form.subcategory) }}
{{ form_widget(form.subcategory) }}
{{ form_end(form) }}
On submit, when checking with Xdebug, the category is the object Category. I can see the correct values present (those chosen in the drop down of the form) but I want just the string, e.g. category.name. How do I do that?
Also, it might need a different question, but when I select one of the categories, I'd like the subcategory to be updated to exclude those that don't belong to that chosen category. I realise this may require jquery.
I'm certain there are better ways, but one solution would be to
$category = $data->getCategory();
$data->setCategory($category->getName());
$data->setSubcategory($category->getSubcategory());
And to exclude the subcategories I use jQuery / JavaScript to retrieve the filtered results from a controller / repository, then remove or add those options in the HTML.

Prevent from display hours input - DateTimeType

I know about options like with_seconds or with_minutes, but im looking for something to stop rendering my hours input in DateTimeType field. For now it looks like this:
My question how is possible to avoid this input in second row ?
Maybe with form themes, but i want to consider with another option.
My RegistrationFormType:
<?php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
class RegistrationType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('sex', ChoiceType::class, array(
'choices' => array(
'Mężczyzna' => 'Mężczyzna',
'Kobieta' => 'Kobieta'
),
'expanded'=> true,
'multiple' => false,
'required' => true
));
$builder->add('birthday_date', DateTimeType::class, array(
'placeholder' => array(
'year' => 'Year', 'month' => 'Month', 'day' => 'Day'
),
'years' => range(1960, 2017),
'with_minutes' => false,
'hours' => array()
));
$builder->add('about_me', TextareaType::class);
}
public function getParent()
{
return 'FOS\UserBundle\Form\Type\RegistrationFormType';
}
public function getBlockPrefix()
{
return 'app_user_registration';
}
}
I'm using FOSUserBundle, so this is my form template for now:
{% trans_default_domain 'FOSUserBundle' %}
{{ form_start(form, {'method': 'post', 'action': path('fos_user_registration_register'), 'attr': {'class': 'fos_user_registration_register'}}) }}
{{ form_widget(form) }}
<div>
<input type="submit" value="{{ 'registration.submit'|trans }}" />
</div>
{{ form_end(form) }}
Thanks you in advance !
Why using DateTimeType if you don't need time ?
Try using DateType or BirthdayType (doc
)

Set class on label attribute of Symfony3 checkbox

I have a symfony3 project where I'm adding a custom class to some form fields via twig. This is all working fine except for the checkbox label. My custom class does not show in the label for the checkbox as expected.
EDIT: adding my form builder:
class ReferralFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('modality', EntityType::class, [
'class' => Modality::class,
'placeholder' => 'Choose modality',
'choice_label' => 'name',
])
->add('referralFromDoctor', EntityType::class, [
'class' => Doctor::class,
'placeholder' => 'Choose a doctor:',
'choice_label' => 'name',
])
->add('isFollowup', CheckboxType::class, [
'label' => 'Follow up visit?',
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Referral::class
]);
}
}
Here's my twig template:
{{ form_start(form) }}
<div id="js-order-wrapper">
{{ form_label(form.modality, 'Type', { 'label_attr': {'class': 'js-hidden-row'} }) }}
{{ form_widget(form.modality, { 'attr': {'class': 'js-hidden-row'} }) }}
{{ form_label(form.referralFromDoctor, 'Ordering clinician', { 'label_attr': {'class': 'js-hidden-row'} }) }}
{{ form_widget(form.referralFromDoctor, { 'attr': {'class': 'js-hidden-row'} }) }}
{{ form_label(form.isFollowup, 'Follow up?', { 'label_attr': {'class': 'js-hidden-row'} }) }}
{{ form_widget(form.isFollowup, { 'attr': {'class': 'js-hidden-row'} }) }}
</div>
{{ form_end(form) }}
and here is the rendered html:
<div id="js-order-wrapper">
<label class="js-hidden-row control-label required" for="referral_form_modality">Type</label>
<select id="referral_form_modality" name="referral_form[modality]" required="required" class="js-hidden-row form-control"><option value="">Choose modality</option></select>
<label class="js-hidden-row control-label required" for="referral_form_referralFromDoctor">Ordering clinician</label>
<select id="referral_form_referralFromDoctor" name="referral_form[referralFromDoctor]" required="required" class="js-hidden-row form-control"><option value="">Choose a doc</option></select
<div class="checkbox">
<label class="required">
<input type="checkbox" id="referral_form_isFollowup" name="referral_form[isFollowup]" required="required" class="js-hidden-row" value="1" /> Follow up visit?
</label>
</div>
</div>
As you can see, the class 'js-hidden-row' is correctly applied to the labels for the fields, but for the checkbox the class is not applied to the label. Seems like a bug to me.
Short of writing a custom block of code to render the checkbox, is there a better solution?

Resources