collection Field Type not creating form elements - symfony

I'm trying to create a form which will add a new text box every time the 'Add new box' link got clicked.
I read through the following example.
http://symfony.com/doc/current/reference/forms/types/collection.html
Basically I was following the example from the book. But when the page is rendered and I click on the link nothing happens.
Any thoughts?
Thanks.
This is my controller.
public function createAction() {
$formBuilder = $this->createFormBuilder();
$formBuilder->add('emails', 'collection', array(
// each item in the array will be an "email" field
'type' => 'email',
'prototype' => true,
'allow_add' => true,
// these options are passed to each "email" type
'options' => array(
'required' => false,
'attr' => array('class' => 'email-box')
),
));
$form = $formBuilder->getForm();
return $this->render('AcmeRecordBundle:Form:create.html.twig', array(
'form' => $form->createView(),
));
}
This is the view.
<form action="..." method="POST" {{ form_enctype(form) }}>
{# store the prototype on the data-prototype attribute #}
<ul id="email-fields-list" data-prototype="{{ form_widget(form.emails.get('prototype')) | e }}">
{% for emailField in form.emails %}
<li>
{{ form_errors(emailField) }}
{{ form_widget(emailField) }}
</li>
{% endfor %}
</ul>
Add another email
</form>
<script type="text/javascript">
// keep track of how many email fields have been rendered
var emailCount = '{{ form.emails | length }}';
jQuery(document).ready(function() {
jQuery('#add-another-email').click(function() {
var emailList = jQuery('#email-fields-list');
// grab the prototype template
var newWidget = emailList.attr('data-prototype');
// replace the "$$name$$" used in the id and name of the prototype
// with a number that's unique to our emails
// end name attribute looks like name="contact[emails][2]"
newWidget = newWidget.replace(/\$\$name\$\$/g, emailCount);
emailCount++;
// create a new list element and add it to our list
var newLi = jQuery('<li></li>').html(newWidget);
newLi.appendTo(jQuery('#email-fields-list'));
return false;
});
})
</script>

This problem can be solved by referring to the following link.
https://github.com/beberlei/AcmePizzaBundle
Here you will find the same functionality being implemented.

I've been through this too.
Answer and examples given to this question and the other question I found did not answer my problem either.
Here is how I did it, in some generic manner.
In generic, I mean, Any collection that I add to the form just need to follow the Form template loop (in a macro, for example) and that's all!
Using which convention
HTML is from Twitter Bootstrap 2.0.x
Javascript code is already in a $(document).ready();
Following Symfony 2.0.x tutorial
Using MopaBootstrapBundle
Form Type class
class OrderForm extends AbstractType
{
// ...
public function buildForm(FormBuilder $builder, array $options)
{
// ...
$builder
->add('sharingusers', 'collection', array(
'type' => new UserForm(),
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
'required'=> false
));
// ...
}
}
JavaScript
/* In the functions section out of document ready */
/**
* Add a new row in a form Collection
*
* Difference from source is that I use Bootstrap convention
* to get the part we are interrested in, the input tag itself and not
* create a new .collection-field block inside the original.
*
* Source: http://symfony.com/doc/current/cookbook/form/form_collections.html
*/
function addTagForm(collectionHolder, newBtn) {
var prototype = collectionHolder.attr('data-prototype');
var p = prototype.replace(/\$\$name\$\$/g, collectionHolder.children().length);
var newFormFromPrototype = $(p);
var buildup = newFormFromPrototype.find(".controls input");
var collectionField = $('<div class="collection-field"></div>').append(buildup);
newBtn.before(collectionField);
}
/* ********** */
$(document).ready(function(){
/* other initializations */
/**
* Form collection behavior
*
* Inspired, but refactored to be re-usable from Source defined below
*
* Source: http://symfony.com/doc/current/cookbook/form/form_collections.html
*/
var formCollectionObj = $('form .behavior-collection');
if(formCollectionObj.length >= 1){
console.log('run.js: document ready "form .behavior-collection" applied on '+formCollectionObj.length+' elements');
var addTagLink = $('<i class="icon-plus-sign"></i> Add');
var newBtn = $('<div class="collection-add"></div>').append(addTagLink);
formCollectionObj.append(newBtn);
addTagLink.on('click', function(e) {
e.preventDefault();
addTagForm(formCollectionObj, newBtn);
});
}
/* other initializations */
});
The form template
Trick here is that I would have had used the original {{ form_widget(form }} but I needed to add some specific to the view form and I could not make it shorter.
And I tried to edit only the targeted field and found out it was a bit complex
Here is how I did it:
{# All form elements prior to the targeted field #}
<div class="control-collection control-group">
<label class="control-label">{{ form_label(form.sharingusers) }}</label>
<div class="controls behavior-collection" data-prototype="{{ form_widget(form.sharingusers.get('prototype'))|escape }}">
{% for user in form.sharingusers %}
{{ form_row(user) }}
{% endfor %}
</div>
</div>
{{ form_rest(form) }}

Related

Symfony render controller

want to display a form in a modal in the header. In order to make the form work I call the controller Homecontroller.
I called the controller with render controller in the branch but I got a blank page.
Thanks for your help.
header.html.Twig
<h1 class="fw-bold"></h1>
<p class="lead fw-bold"></p>
{{include ('fragments/modal_form.html.twig') }}
</main>
</div>
</div>
modal_form.html.twig
{{ render(controller(
'App\\Controller\\HomeController::index',{'form' : form.createForm()} )) }}
</div>
Controller :
* #Route("/", name="home")
*/
public function index(PostsRepository $postsRepository,TagRepository $tagRepository, Request $request ):Response
{
$listTag = $tagRepository->findAll();
$listPost = $postsRepository->findByPostPHp('php');
$posts = $postsRepository->findByExampleField($value = 6);
$partage = New Posts();
$form = $this->createForm(PartagePostType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$partage = $form->getData();
$this->entityManager->persist($partage);
$this->entityManager->flush();
$this->addFlash('success', 'Votre post a bien été partagé');
}
return $this->render('home/index.html.twig', [
'posts' => $posts,
'tag' => $listTag,
'listPost' => $listPost,
'form' => $form->createView(),
]);
}
I dont' really get how you are trying to render you form but it doesn't work that way, in your modal_form.html.twig you should use the {{ form_start() }} and {{ form_end() }} twig helpers. They take in parameters the created view of the form, i.e, the variable "form" in your case (created in your render with the createView() method).
It should look like that:
{{ form_start(form}}
{{ form_row(form.field) }}
<input type="submit" value="submit">
{{ form_end(form) }}
"field" is whatever name you defined in your FormType. Notice how I added raw HTML for the submit button, it is suggested by Symfony you add the send button that way, even though you can add it in your FormType.
You can learn more about form rendering here : How to Customize Form Rendering
And forms in general there : Forms
Last thing, if you want to use multiple forms with this modal, don't forget to change the name of the variable (also don't forget to add this variable in your controller when you render a template with a form in it, obviously)

Symfony Form Builder: How to dynamically add Fields to a Poll

I created a Symfony Poll-Bundle which has the Entitys Campaign->Block->Line->Field->PollResult.
So i have a CollectionType CampaignType which consists of many blocks.
One block consist of many Lines.
One Line consist of many Fields.
(One Line is for example the line for fever and the fields are for intensity, and the period from and due the fever occured)
And every Field has one PollResult which holds the Answer of the user who filled out the campaign.
Now i want to make the user to be able to add new Fields to a line to enter a second fever period for example.
So i need a 'Add a Line'-Button for every Line that duplicates this line.
I used this documentation to do that.
First i added 'allow_add' => true to my LineType FormBuilder:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('userAddFlag');
$builder->add('fields', CollectionType::class, array(
'entry_type' => FieldType::class,
'entry_options' => array('label' => false),
'allow_add' => true,
));
}
Then i added this to my view with the data-prototype:
<ul class="fields" data-prototype=" {{ form_widget(line.fields.vars.prototype)|e('html_attr') }} ">
<li>
{% for field in line.fields %}
<div>
{% for pollResult in field.pollResults %}
<div class="formLabelDiv">{{ field.vars.value.getTranslationName(app.request.getLocale()) }}</div>
<div class="formWidgetDiv">{{ form_widget(pollResult) }}</div>
{% endfor %}
</div>
{% endfor %}
</li>
</ul>
And last i added this jQuery code:
<script>
var $collectionHolder;
//setup an "add a Line" Link
var $addLineButton = $('<button type="button" class="add_line_link">Add a Line</button>');
var $newLinkLi = $('<li></li>').append($addLineButton);
jQuery(document).ready(function (){
//Get the ul that holds the collection of fields
$collectionHolder = $('ul.fields');
//add the "add a line" anchor and li to the tags ul
$collectionHolder.append($newLinkLi);
//count the current form inputs we have, use that as the new index when inserting a new item
$collectionHolder.data('index', $collectionHolder.find(':input').length);
$addLineButton.on('click', function (e){
addFieldsForm($collectionHolder, $newLinkLi);
})
})
function addFieldsForm($collectionHolder, $newLinkLi){
//get the data-prototyp
var prototype = $collectionHolder.data('prototype');
//get the new index
var index = $collectionHolder.data('index');
var newForm = prototype;
$collectionHolder.data('index', index+1);
// Display the form in the page in an li, before the "Add a tag" link li
var $newFormLi = $('<li></li>').append(newForm);
$newLinkLi.before($newFormLi);
}
</script>
So now the 'Add a Line'-Button appears on the page, but it doesn't add anything..
How can i add a new field and how am i able to duplicate the whole line and not only add one Field to the added line (I want to have the three fields intensity(dropdown), from and due(both textfield with datepicker))
Try adding 'by_reference' => false, to the LineType.php

render a user image and account link in the menu.html.twig

I want to display a user picture (avatar) and some more fields in the menu.html.twig template.
I know that we can display these fields in a user.html.twig template.
{{ content.user_picture }}
{{ user.getDisplayName() }}
{{ content.field_name_user[0] }}
and etc.
But I want to display these fields in the menu.html.twig template.
As I think. we can make a variable in preprocess_block () and print the desired value.
Or if there is no necessary variable in the template - do it in the preprocessor of this template!
Help please make a decision on this issue. And what code you need to write.
It is better to write a pre-process and define a variable and insert the desired elements in it.
hook_preprocess_menu__menu_name(array &$variables) {
$userDetails = \Drupal\user\Entity\User::load(\Drupal::currentUser()->id());
/**
fetch the desired elements and pass to $variables eg:
**/
$variables['userPictureUrl'] = $userDetails->user_picture->entity->url();
}
You can use hook_preprocess_menu:
function YOURMODULE_preprocess_menu(&$variables)
{
$uid = \Drupal::currentUser()->id();
if($uid > 0)
{
// Load user
$user = User::load($uid);
$userName = $user->getUsername();
// If user have a picture, add it to variable
if(!$user->user_picture->isEmpty()){
$pictureUri = $user->user_picture->entity->getFileUri();
// Add style to picture
$userPicture = [
'#theme' => 'image_style',
'#style_name' => 'profile_picture',
'#uri' => $pictureUri,
];
}
// Set variables
$variables['MYMODULE'] = [
'profile_name' => $userName,
'profile_picture' => $userPicture,
'profile_id' => $userId
];
}
}
End show in your menu.html.twig file:
{{ YOURMODULE.profile_name }}
{{ YOURMODULE.profile_picture }}
{{ YOURMODULE.profile_id }}

Get value from collection field in Twig

I have collection form and need to access the value to show in my view. The problem is seems the key variable declared as Integer and I got error like this :
Impossible to access an attribute ("nama") on a integer variable ("0")
in SifoAdminBundle:DftAbsensi:manage.html.twig at line 65
Here my Twig :
{% for key, absensi in form_edit %}
<li>{{ form_edit.vars.value.statusS.key.nama }}</li>
{% endfor %}
If I change {{ form_edit.vars.value.statusS.key.nama }} into {{ form_edit.vars.value.statusS.1.nama }} its works fine.
Here my controller :
/* Show data */
$emShow = $this->getDoctrine()->getManager();
$collectionAbsensi = new CollectionAbsensi();
foreach ($entityGrupPelajar as $temp) {
$entity = new DftAbsensi();
$entity = $emShow->getRepository('SifoAdminBundle:DftAbsensi')->findOneBy(array('idGrupPelajar' => $temp, 'tanggal' => $tanggal));
if ($entity)
{
$entityPelajar = $emShow->getRepository('SifoAdminBundle:MstPelajar')->find($temp->getIdPelajar());
$dftAbsensi = new DftAbsensi();
$dftAbsensi->setId($entity->getId())
->setIdGrupPelajar($entity->getIdGrupPelajar())
->setTanggal($entity->getTanggal())
->setStatus($entity->getStatus())
->setNis($entityPelajar->getNis())
->setNama($entityPelajar->getNama())
;
$collectionAbsensi->getStatusS()->add($dftAbsensi);
}
}
$emShow->flush();
$formEdit = $this->createForm(new CollectionAbsensiType(), $collectionAbsensi);
$formEdit->add('save', 'submit', array('attr' => array('class' => 'btn btn-info')));
return $this->render('SifoAdminBundle:DftAbsensi:manage.html.twig', array(
'form_edit' => $formEdit->createView(),
));
I have searched for this problem also read the issue #902 but still this problems occurs in my Symfony 2.4 on PHP 5.4
Is there any ways to get that value in iteration without key?
Try changing
form_edit.vars.value.statusS.key.nama
To
form_edit.vars.value.statusS[key].nama
The former is equivalent to $form_edit['vars']['value']['statusS']['key']['nama'] (which does not exist) while the latter is equivalent to $form_edit['vars']['value']['statusS'][$key]['nama']

symfony 2 - twig - How view more (20) fields with use "prototype"?

I want view 20 same fields (name: matchday) with use "prototype".
I have a code like this:
Form:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('matchday', 'collection', array(
'allow_add' => true,
'type' => new MatchdayType(),
))
...
}
and View (Twig):
<form action="{{ path('meet_create') }}" method="post" {{ form_enctype(form) }}>
{% for i in 1..20 %}
{{ form_widget(form.matchday.vars.prototype) }}
{% endfor %}
<p>
<button type="submit">Create</button>
</p>
</form>
but I don' know how use iteration in this code with "prototype" .
thanks
The prototype is only a model that you can use to create new fields in the form's collection, but it's not really a field per say. If you want to display 20 empty fields from the beginning, you have basically two choices:
add 20 empty 'matchday' objects in the form object in your controller before creating the form
use Javascript (jQuery) to add the fields in the view on the client side
The first solution would give something like this:
$meet = new Meet();
for ($i=0; $i < 20; $i++) {
$matchday = new MatchDay();
$meet->getMatchdays->add($matchday);
}
$form = $this->createForm(new MeetType(), $meet);
For the second solution, you have a good example in the Symfony Cookbook about form collection: http://symfony.com/doc/current/cookbook/form/form_collections.html

Resources