Display repeated field type in Symfony2 - forms

I have a password repeated field type in Symfony2 form that goes like this:
->add('password', 'repeated', array(
'type' => 'password',
'invalid_message' => 'Les mots de passe doivent correspondre',
'options' => array('required' => true),
'first_options' => array('label' => 'Mot de passe'),
'second_options' => array('label' => 'Mot de passe (validation)'),
'required' => $bRequired,
'trim' => true,
'constraints' => array(
new Assert\Regex(array(
'pattern' => "/^(?=.*[0-9])(?=.*[a-z])[a-zA-Z0-9!?+]{8,15}$/",
'match' => true,
'message' => "msg"
)),
new Constraints\NotBlank(),
)
))
In twig I'm used to show this field like this:
{% for passwordField in form.password %}
{{ form_row(passwordField,{'attr': { 'class': 'form-control'} }) }}
{% endfor %}
I'm wondering if there is a way to display the password field and the validation field separately so I can display them in different places in my form.

As it is explained in doc:
// in your template.html.twig
/.../
{{ form_row(form.password.first,{'attr': { 'class': 'form-control'} }) }}
{{ form_row(form.password.second,{'attr': { 'class': 'form-control'} }) }}
/.../
where:
The names first and second are the default names for the two sub-fields. However, these names can be controlled via the first_name and second_name options. If you've set these options, then use those values instead of first and second when rendering.

Related

Symfony2 - NotBlank constraint not working on EntityType

I have two EntityType fields in my form and both has NotBlank constraint assigned to them.
Now, I have this issue that NotBlank constraint is not working only on one field with multiple => true set on.
$builder
->add('preferredCountries', EntityType::class, array(
'required' => false,
'class' => 'IndexBundle:Country',
'property' => 'name',
'empty_value' => 'Choose',
'multiple' => true,
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('c')
->where('c.name != :name')
->orderBy('c.name', 'ASC')
->setParameter('name', 'Other');
},
'constraints' => array(
new NotBlank(array(
'message' => 'blank!!!',
)),
)
))
->add('internshipProgram', EntityType::class, array(
'required' => false,
'class' => 'IndexBundle:InternshipProgram',
'property' => 'name',
'empty_value' => 'Choose',
'constraints' => array(
new NotBlank(array(
'message' => 'blank!!!',
)),
)
))
In this case when I submit empty values, field internshipProgram get an error, and prefferedCountries not.
Form display:
<div class="form-group col-xs-12">
{{ form_label(current_internship_form.preferredCountries, 'Preferred countries', { 'label_attr': {'class': 'label-text'} }) }}
{{ form_widget(current_internship_form.preferredCountries) }}
<span class="error text-danger small">{{ form_errors(current_internship_form.preferredCountries) }}</span>
</div>
<div class="form-group col-xs-12">
{{ form_label(current_internship_form.internshipProgram, 'What type of training agreement will you have?', { 'label_attr': {'class': 'label-text'} }) }}
{{ form_widget(current_internship_form.internshipProgram, { 'id': 'internship_program', 'attr': {'class': 'form-control '}}) }}
<span class="error text-danger small">{{ form_errors(current_internship_form.internshipProgram) }}</span>
</div>
Is there a mistake in my code or is it somehow related to multiple choice selection? Has anyone had similar issue and know how to solve it?
You can't use NotBlank constraint on EntityType with multiple set to true. As the array will never be null. You should try using the count constraint like this:
$builder
->add('preferredCountries', EntityType::class, array(
'required' => false,
'class' => 'IndexBundle:Country',
'property' => 'name',
'empty_value' => 'Choose',
'multiple' => true,
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('c')
->where('c.name != :name')
->orderBy('c.name', 'ASC')
->setParameter('name', 'Other');
},
'constraints' => array(
new Count(array(
'min' => 1,
'minMessage' => "Should not be blank"
))
)
))
...
Also you can specify at Entity level,
/**
* #Count(min = 1, minMessage = "At least one branch must be selected")
*/
protected $multiCheckBox;

Collection of form embedded is showing the whole form insetead of a single field

I'm following the official documentation example but I can't make it to work properly.
Summarizing, I have material and items_budget table. Both of them are related as oneToMany and manyToOne, by the id and material fields:
Material.orm.yml:
oneToMany:
itemsBudget:
targetEntity: ItemsBudget
mappedBy: material
ItemsBudget.orm.yml:
material:
targetEntity: Material
inversedBy: itemsBudget
joinColumn:
name: material
referencedColumnName: id
Here, the ItemsBudgetType where I set the material field as a collection:
$builder->add('budget', 'entity', array(
'class' => 'PanelBundle:Budget',
'attr' => array(
'class' => 'form-control',
),
))
->add('material', 'collection', array(
'type' => new MaterialType(),
'allow_add' => true
))
->add('quantity', 'number', array(
'attr' => array(
'class' => 'form-control',
),
))
->add('price', 'money', array(
'attr' => array(
'class' => 'form-control',
),
));
Just for information, the MaterialType:
$builder->add('name', 'text', array(
'attr' => array(
'class' => 'form-control',
),
))
->add('description', 'text', array(
'attr' => array(
'class' => 'form-control',
),
))
->add('current_quantity', 'text', array(
'attr' => array(
'class' => 'form-control',
'required' => false
),
))
->add('price', 'money', array(
'attr' => array(
'class' => 'form-control',
),
));
Here the index.html.twig of my ItemsBudget view:
<strong>Materiais</strong>
<div class="form-group">
<ul class="materials" data-prototype="{{ form_widget(form.material.vars.prototype)|e }}">
{% for material in form.material %}
<li>{{ form_widget(form.material.vars.prototype.name) }}</li>
{% endfor %}
</ul>
</div>
In the view, I have tried also as it is in the example: {{ form_row(material.name) }}, but it still shows the whole Material form.
And where I'm calling them, in the ItemsBudgetController:
public function addAction(Request $request)
{
$form = $this->createForm(new ItemsBudgetType(), new ItemsBudget());
$manager = $this->getDoctrine()->getManager();
if ($request->getMethod() == 'POST') {
$form->handleRequest($request);
if ($form->isValid()) {
$ItemsBudgetEntity = $form->getData();
$manager->persist($ItemsBudgetEntity);
$manager->flush();
$BudgetEntity = $form->get('budget')->getData();
$BudgetEntity->addItemsBudget($ItemsBudgetEntity);
$manager->persist($BudgetEntity);
$manager->flush();
$this->addFlash('success', 'Materiais para o orçamento adicionados');
return $this->redirect($this->generateUrl('panel_budgets'));
}
}
return $this->render('PanelBundle:ItemsBudget:index.html.twig', array(
'form' => $form->createView(),
'budgets' => $manager->getRepository('PanelBundle:Budget')->findAll()
));
}
The JavaScript is the same from the example too:
function addMaterial($collectionHolder, $newLinkLi) {
var prototype = $collectionHolder.data('prototype');
var index = $collectionHolder.data('index');
var newForm = prototype.replace(/__name__/g, index);
$collectionHolder.data('index', index + 1);
var $newFormLi = $('<li></li>').append(newForm);
$newLinkLi.before($newFormLi);
}
var $collectionHolder;
var addMaterialLink = $('Mais');
var $newLinkLi = $('<li></li>').append(addMaterialLink);
jQuery(document).ready(function () {
$collectionHolder = $('ul.materials');
$collectionHolder.append($newLinkLi);
$collectionHolder.data('index', $collectionHolder.find(':input').length);
addMaterialLink.on('click', function (e) {
e.preventDefault();
addMaterial($collectionHolder, $newLinkLi);
});
});
This is the issue: instead of showing only the name field from Material form, it is showing the whole form every time I click the "Mais". Am I missing something?
The javascript takes the content of the data-prototype attribute and appends it to the html of the form. The attribute in your template contains {{ form_widget(form.material.vars.prototype)|e }} which is the html prototype of the form.
Try:
<ul class="materials" data-prototype="{{ form_widget(form.material.vars.prototype.name) }}">

Symfony, Hidden Form Field

i have problem with hiding my form fields. For example:
->add('new_password', 'repeated', array(
'first_options' => array(
'label' => 'Nowe hasło',
'attr' => array('style'=>'display:none;')),
'second_options' => array(
'label' => 'Powtórz nowe hasło',
'attr' => array('style'=>'display:none;')),
'mapped' => false,
'required' => false,
));
Field is not visible but label is visible. I want to have hidden field but label should be hidden to. I want to show it in Jquery after clicking on the button. Any ideas guys ?
First, this is not a Hidden Field Type but a repeated type you want to hide by passing a style='display:none;' attribute.
In general, if you don't want to display a given label, you may need to customize your form rendering.
For example,
{{ form_row(yourForm.new_password) }} {# in case you're using the form_row helper #}
should be replaced by
{{form_widget(yourForm.new_password) }}
Because form_row(yourForm.yourField) is in fact a shortcut for,
{{ form_errors(yourForm.yourField) }}
{{ form_label(yourForm.yourField) }}
{{ form_widget(yourForm.yourField) }}
Also,
Why do you need to hide a repeated password field this way?
If you want to show it only when you click on a button why dont you wrap the newPassword widget in a div with display none?
But if you want to add attributes to the label you can use the option label_attr like this:
{{ form_row(form.name, {'label_attr ':{'class':'hidden'}}) }}
or
->add('new_password', 'repeated', array(
'first_options' => array(
'label' => 'Nowe hasło',
'label_attr' => array('style'=>'display:none;')),
'second_options' => array(
'label' => 'Powtórz nowe hasło',
'label_attr' => array('style'=>'display:none;')),
'mapped' => false,
'required' => false,
));

symfony 2, form_rest(form) shows collection fields

My form has 3 collection fields:
$builder->add('affiliates', 'collection', array(
'type' => new AffiliateForm(),
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
'options' => array(
'affiliate_types' => $options['affiliate_types'],
'business_types' => $options['business_types'],
),
));
$builder->add('other_businesses', 'collection', array(
'type' => new OtherBusinessForm(),
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
));
$builder->add('welfare_activities', 'collection', array(
'type' => new WelfareActivityForm(),
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
'options' => array(
'welfare_activity_types' => $options['welfare_activity_types'],
),
));
In the template I show each subform field separately one by one, like below:
<td class="t1c5" >{{ form_widget(affiliate.location) }}
{{ form_errors(affiliate.location) }}</td>
At the end of the form I did:
{{ form_rest(form) }}
But it causes to display the following words at the end of form, when given collection is empty: "Affiliates", "Other businesses", "Welfare activities".
So the question is:
Why those words are displayed on the form?
I can do the following to avoid the above issue:
<div style="display:none;">{{ form_rest(form) }}</div>
Is it correct way of dealing with the problem (maybe i can make a field hidden or whatever)?
Thank you.
those words are displayed on the form because you forget :
{{ form_label(affiliate.location) }}
…
…
According to the doc :
form_rest(view, variables)
This renders all fields that have not yet been rendered for the given form. It's a good idea to always have this somewhere inside your form as it'll render hidden fields for you and make any fields you forgot to render more obvious (since it'll render the field for you).
{{ form_end(form, {'render_rest': false}) }}

Symfony2 form collection with checkboxes

I'm building a form with Symfony2 and need to group some checkboxes. I simply cannot figure out how to pass choices/label along to the checkboxes in BonusGroup.
Form:
$builder->add('groups', 'collection', array(
'type' => new BonusGroup(),
'allow_add' => false,
'allow_delete' => false,
'by_reference' => false
));
BonusGroup():
$builder->add('bonus', 'choice', array(
'choices' => $options['bonus'],
'multiple' => true,
'expanded' => true
));
View.twig:
{% for group in form.groups %}
{{ form_label(group) }}
{% for final in group.bonus %}
{{ form_widget(final) }}
{% endfor %}
{% endfor %}
Passing data to form:
$data = array(
'groups' =>
array ('Group 1 label' => array())
);
$form = $app['form.factory']->createBuilder(new Form(), $data))->getForm();
Any tips?
Thanks!
First, change form_widget to form_row, but it won't work yet because collection type need a piece of JavaScript to work.
See examples here:
http://symfony.com/doc/2.1/reference/forms/types/collection.html