I have some problem. I need add in registration template in FOSUserBundle calendar which allows choose birthday user's - the standard html tag date doesn't fit. To order to do this I used datepicker of jQuery:
<link rel="stylesheet" href="//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css">
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
<link rel="stylesheet" href="/resources/demos/style.css">
<script>
$(function () {
$("#fos_user_registration_form_birthday").datepicker({
changeMonth: true,
changeYear: true,
yearRange: '1950:2010',
});
});
</script>
<form action="{{ path('fos_user_registration_register') }}" {{ form_enctype(form) }} method="POST" class="fos_user_registration_register">
{{ form_errors(form) }}
<ol>
[.........]
<li>
{{ form_label(form.birthday) }}
{{ form_widget(form.birthday) }}
{{ form_errors(form.birthday) }}
{{ form_rest(form) }}
</li>
<input type="submit" value="{{ 'registration.submit'|trans }}" />
</li>
</ol>
[.........]
</form>
It's working fine, but if I override the template and add:
{%extends 'MyBlogBundle::layout.html.twig'%}
{% block content %}
[ form registration]
{% endblock%}
It doesn't work.
So, what am I doing wrong?
And I have one more than question - how to add or change class, id in registration form? I tried it in template
{{ form_widget(form.birthday {'attr': {'class': 'task_field'}}) }}
and in RegistrarionFormType:
->add('birthday','text',array('attr'=>array('id'=>'text_field')))
But id doesn't change.
Hi I'm kinda new to this domain but I believe you should include
{% block fos_user_content %}
in your main template or overwrite them totaly in your own bundle (your bundle class should then contain getParent() method)
I believe the main template lives in (if your bundle is named UserBundle)
UserBundle\Resources\views\layout.html.twig
the most basic overwrite would then be
{# UserBundle\Resources\views\layout.html.twig #}
{% extends '::base.html.twig' %}
{% block body %}
{{ block('fos_user_content') }}
{% endblock %}
// UserBundle\UserBundle.php
namespace UserBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class UserBundle extends Bundle
{
public function getParent()
{
return "FOSUserBundle";
}
}
After that you can copy the templates you want to overload to corresponding bundle folder eg
UserBundle\Resources\views\Registration\xx.html.twig
from the FOSUserBundle.
After changing the "include strategy" in your project you must clear your cache also in DEV mode otherwise you wil not see the changes. Changes applied to the content do not need a clearing of your cache.
Related
I have this form:
class BillType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('user')
->add('numberPlate')
->add('servicesPerformed', CollectionType::class, array(
'label' => false,
'entry_type' => ServicePerformedType::class,
'allow_add' => true,
))
->add('Save', SubmitType::class)
;
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'DefaultBundle\Entity\Bill'
));
}
being ServicePerformedType class this:
class ServicePerformedType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('description', TextareaType::class, array('label' => false))
->add('price', TextType::class, array('label' => false))
->add('quantity', TextType::class, array('label' => false));
}
}
And this template to render the form:
{{ form(form) }}
Add service
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<script type="text/javascript">
var index = 0;
$('a').on('click', function() {
var prototype = $('#bill_servicesPerformed').data('prototype');
prototype = prototype.replace(/_name_/g, index.toString());
$('#bill_servicesPerformed').html(prototype);
index++;
})
</script>
As it is said in the docs, to get a custom prototype I should add the lines below at the top of my template:
{% form_theme form _self %}
{% block _servicesPerformed_entry_widget %}
I WILL WRITE MY CUSTOM PROTOTYPE HERE
{% endblock %}
But when I press Add service I dont get the text I WILL WRITE MY CUSTOME PROTOTYPE HERE, but the description, fields and quantity related to the ServicePerformedType class as before..
NOTE: maybe there are other ways to custom a form prototype, but I'm interested on this, so will be very thankful to someone who give a solution related to this way to custom form prototypes, thanks.
I must warn you that customizing the prototype could be a bit tricky. If you change your FormType fields you'll need to go through the template and make the same changes as well or your form will fail to render.
What I like to do is to create a custom template for that specific field and then customize it appropriately. So, looking at your code I would do something like this:
Create a page template - the one you'll use to render the entire page, including the form.
{# MyBundle/Resources/views/myPage.html.twig #}
{% extends "::base.html.twig" %}
{# This will tell the form_theme to apply the
`MyBundle:form/fields/servicePerformed.html.twig` template to your "form" #}
{% form_theme form with [
'MyBundle:form/fields/servicePerformed.html.twig'
] %}
{% block body %}
<div>
{{ form_start(form) }}
{{ form_rest(form) }}
{{ form_end(form) }}
</div>
{% endblock %}
Now you'll need to create the template MyBundle/Resources/views/form/fields/servicePerformed.html.twig. It will be used to customize only the servicePerformed field. The template should look something like this
{% macro service_template(fields) %}
<tr>
<td>I WILL WRITE MY CUSTOM PROTOTYPE HERE</td>
</tr>
{% endmacro %}
{#
The block name must match your field name!
You can find it by going into the debug toolbar -> Forms ->
click on your form field and then search for "unique_block_prefix".
Copy that and add "_widget" at the end.
#}
{% block _service_performed_widget %}
<table data-prototype="{{ _self.service_template(form.vars.prototype)|e }}">
{% for fields in form.children %}
{{ _self.service_template(fields) }}
{% endfor %}
</table>
{% endblock %}
I want to note that in the field template I'm passing the original prototype _self.service_template(form.vars.prototype). By doing this, you can use the original fields and render them in your customized prototype. For example this code:
{% macro service_template(fields) %}
<tr>
<td>{{ form_widget(fields.description) }}</td>
</tr>
{% endmacro %}
Will result in something like the following rendered prorotype:
<tr>
<td>
<input type="text" id="service_performed___name___description" name="service[__name__][description]"/>
</td>
</tr>
You can then manipulate it using your javascript.
I hope this helps you.
Actually form theme blocks that start with an underscore _ relate to a field with a specific name.
What I mean is that, if your master form BillType is called my_form, you will need to do this:
{% form_theme form _self %}
{% block _my_form_servicesPerformed_entry_widget %}
I WILL WRITE MY CUSTOM PROTOTYPE HERE
{% endblock %}
The problem with this approach is that it concerns a specific iteration of BillType. If you use this form type elsewhere and provide it with a different name my_form_2, you would have to add an identical block named _my_form_2_servicesPerformed_entry_widget.
You can use macro, have a look at below example it's working fine for me even in Symfony3. Using this example you will be able to format your collection prototype as well.
View
{% macro widget_prototype(widget, remove_text) %}
{% if widget.vars.prototype %}
{% set form = widget.vars.prototype %}
{% set name = widget.vars.name %}
{% else %}
{% set form = widget %}
{% set name = widget.vars.full_name %}
{% endif %}
<div data-content="{{ name }}" class="panel panel-default">
<div class="section row">
<div class="col-md-12">
<label class="field-label">Skill <span class="text-danger">*</span></label>
<label class="field select">
{{ form_widget(form.skill) }}
<i class="arrow double"></i>
</label>
</div>
</div>
<div data-content="{{ name }}">
<a class="btn-remove" data-related="{{ name }}">{{ remove_text }}</a>
{{ form_widget(form) }}
</div>
</div>
{% endmacro %}
Your template to render the form has some problems. The first is this line:
prototype = prototype.replace(/_name_/g, index.toString());
The regex should be __name__.
Next, you are retrieving the prototype, but then immediately overwriting it and replacing the HTML of the prototype. There is nothing there I can see that actually appends the new form to your existing form anywhere. Plus since you just have a string of text, that replace isn't going to find any text __name__ to replace.
You should post the full extent of your Twig/Javascript so we can actually see the #bill_servicesPerformed as well as everything else you are trying to do. Before you write a custom prototype you should get the form working with the standard prototype just to make sure you don't have any bugs there first.
As an example, this is the way I keep going it. I do not know if there are some reasons not to, so be careful.
Form to include prototype:
<div class="modal-body" id="contactMehtods" data-prototype="
{% filter escape %}
{{ include(':organization/partials:prototype_contact_method.html.twig', { 'contact_method': contact_form.contactMethods.vars.prototype }) }}
{% endfilter %}">
<div class="form-group">
{{ form_label(contact_form.name, null, { 'label_attr': { 'class': 'control-label' }}) }}
{{ form_widget(contact_form.name, {'attr': {'class': 'form-control'}}) }}
</div>
</div>
Prototype template:
<div class="form-group">
{{ form_label(contact_method.name, null, { 'label_attr': { 'class': 'col-sm-3 control-label' }}) }}
<div class="col-sm-9">
{{ form_widget(contact_method.name, {'attr': {'class': 'form-control'}}) }}
</div>
</div>
<div class="form-group">
{{ form_label(contact_method.value, null, { 'label_attr': { 'class': 'col-sm-3 control-label' }}) }}
<div class="col-sm-9">
{{ form_widget(contact_method.value, {'attr': {'class': 'form-control'}}) }}
</div>
</div>
But a note to consider, the javascript needs to accommodate for these changes I guess.
How to alter the fields.html.twig template?
I am only looking for the "hello world" equivalent to see the first ever change to the form.
What's working (within a bundle view as add.Article.html.twig):
<div class="well;">
<form method="post" {{ form_enctype(form) }}>
{{ form_widget(form,{attr: {class:'test'}} ) }}
<input type="submit" class="btn btn-primary" />
</form>
</div>
The test class is only doing a CSS .test{background-color:grey;}. I am normally using Bootstrap.
In fields.html.twig I have:
{% block aliquam_input %}
{% spaceless %}
<div>
{{ form_label(form) }}
{{ form_errors(form) }}
{{ form_widget(form, { 'attr': {'class': 'test'} }) }}
</div>
{% endspaceless %}
{% endblock %}
and in app/config/config.yml:
# Twig Configuration
twig:
//..
form:
resources:
- 'AliquamSummaryBundle:Form:fields.html.twig'
The fields.html.twig is rendered ok to the main twig as I get an error when removing one of the hash in the fields twig.
What's not working (i.e. class test doesn't show) is when I try to make the fields.html.twig take effect on Article.html.twig:
{% block aliquam_input %}
{% spaceless %}
<div class="well;">
<form method="post" {{ form_enctype(form) }}>
{{ form_widget(form) }}
<input type="submit" class="btn btn-primary" />
</form>
</div>
{% endspaceless %}
{% endblock %}
As all forms will have the same format, I'd prefer to not set all html attributes to every single line. But what is the way to get the class "test" taking effect from the fields.html.twig template?
___________________________ Update for David _____________
Thanks #David, but unfortunately adding the name as form.name doesn’t change anything. The CSS attribute is still not transferred to the form in html. Well spot for the semicolon after well; it was a late night typo, but not related to the problem.
Here is what I have figured so far. I might have to end up having to enter bootstrap CSS to each individual row in a form (horrible thought) or figure how to do this by entities options, which comes almost to the same horrible thought as doing it for every row. Since the doc offers to enter a template for all forms via app/config/config.yml there should be a far simpler way, but I don’t get it.
The below is the only direction so far which made CSS work a little, i.e. class .test{background-color: black;} is doing its job:
{# ..\addArticle.html.twig #}
<div class="well">
<form method="post" {{ form_enctype(form) }}>
{{ form_widget(form) }}
<input type="submit" class="btn btn-primary" />
</form>
</div>
NB: there is no {% block .. %} around the div, which makes sense as I put the fields.html.twig to be included to the symphony standard widgets through app/config/config.yml. The above goes with the fields.html.twig below.
{# ..\fields.html.twig #}
{% block widget_attributes %}
{% spaceless %}
{{" class=\'test\'" }}
{% endspaceless %}
{% endblock widget_attributes %}
So far only fields with textarea show black color, bit it’s kind of “hello world”. I am not sure if this is right way to proceed as I have not found anything alike in this and other forums and the doc only states to look at form_div_layout.html.twig on git to decide which attribute to change, which is not really helpful (to me).
First change your well; class to well in your add.Article.html.twig.
In order to put a class on your widget I think you can try
{{ form_widget(form.name, {'attr': {'class': 'test'}}) }}
The difference with your code is the form.name parameter. If you only give the form it will not apply passed options. See the doc
Changing the fields.html.twig as
{# ..\fields.html.twig #}
{% block widget_attributes %}
{% spaceless %}
{{" class=\'test\'" }}
{% endspaceless %}
{% endblock widget_attributes %}
is indeed correct in what concerns Symfony and the reason that with bootstrap-CSS only the textareas show the class="test" is that bootstrap assigns mandatorily (all other than textareas) with the bootstrap specific one.
As I don't want to alter the bootstrap as such I ended up assigning the attributes per widget from within the entities - anything else would probably opening a can of worms.
I have following twig block in template which extends main layout:
{% block abc %}
{{ name }}
{% endblock %}
next I have a head block in the same template. I want to pass block abc as template for twig.js:
{% block head %}
<script type="text/html" id="template-abc">
{{ blocksource('abc') }}
</script>
{% endblock %}
so the rendering result is:
{{name}}
How can I do this?
I tried building "blocksource" function in twig extension, but I don't know how to access block source form here.
function blocksource( Twig_Environment $env, $blockname) {
$source = ???;
return $source;
}
Use verbatim tag, it will do what you want.
{% verbatim %}
{{ things_you_want_to_show_as_twig_template }}
{% endverbatim %}
Everything inside this tag will not be interpreted by twig engine.
You can read more on that in twig documentation.
I have a Entity Type form where I list all the friends of the current user. This is e.g. used for creating a new Group. Now I want to use the same form for adding people to the same group, so the Choice field should show all the friends of the current user that are not yet in the group. I thought I just use a form event to remove the options(users) that are already in the group.
My listener looks like this:
class FriendSelectListener implements EventSubscriberInterface {
public static function getSubscribedEvents() {
// Tells the dispatcher that we want to listen on the form.pre_set_data
// event and that the preSetData method should be called.
return array(FormEvents::PRE_SET_DATA => 'preSetData');
}
public function preSetData(FormEvent $event) {
$betRound = $event->getData();
$form = $event->getForm();
$groupForm = $form->get('userGroup');
$usersForm = $groupForm->get('users');
foreach($betRound->getUserGroup()->getUsers() as $user){
if($usersForm->has($user->getId())){
$usersForm->remove($user->getId());
}
}
}
}
But I can't render it, because in my test I removed the user with the id 2 and then I get the following error message while rendering:
Key "2" in object (with ArrayAccess) of type
"Symfony\Component\Form\FormView" does not exist in
/var/lib/stickshift/1ed1210eec124c179c45aac4ad484afd/app-root/data/269891/src/Strego/UserBundle/Resources/views/Form/selectFriends.html.twig
at line 5
Update:
This might be related to my view:
{% for id, choice in choices %}
{% set user = choice.data %}
<label>
<div class="people-list people-choose unselected" style="width:270px;">
<img src="{{ user.profilePic | imagine_filter('profile_thumb') }}" class="img-polaroid" alt="{{ user.nickname }}">
{#<img src="{{ asset('bundles/stregoapp/img/profile-thumb-90x90.png') }}" alt="Profilbild" class="img-polaroid">#}
<p>{{ form_widget(form[id]) }} <span class="label">einladen</span></p>
<h3>{{ user.nickname }}</h3>
<h3><small>{{ user.firstName }} {{ user.lastName }}</small></h3>
</div>
</label>
{% endfor %}
For me it seems like I only removed the form element but not the choice.
I found the problem, it was indeed my view. As soon as I stopped iterating over the options but used the child elemts of my form element it was working:
{% for child in form %}
{% set user = choices[child.vars.value].data %}
<label>
<div class="people-list people-choose unselected" style="width:270px;">
<img src="{{ user.profilePic | imagine_filter('profile_thumb') }}" class="img-polaroid" alt="{{ user.nickname }}">
<p>{{ form_widget(child) }} <span class="label">einladen</span></p>
<h3>{{ user.nickname }}</h3>
<h3><small>{{ user.firstName }} {{ user.lastName }}</small></h3>
</div>
</label>
{% endfor %}
I need to output a portion of client-side handlebars templates, which has tags similar to twig's 'say' tags:
<script type="text/x-handlebars">
{{#view App.MyView}}
<h1>Hello world!</h1>
{{/view}}
</script>
And twig attempts to parse these templates. How do I prevent it? Is it possible to mark a section of a template as plain text?
There is raw tag for this purpose:
<script type="text/x-handlebars">
{% raw %}
{{#view App.MyView}}
<h1>Hello world!</h1>
{{/view}}
{% endraw %}
</script>
Update
As raw tag is deprecated use verbatim instead.
{% raw %} deprecated
{% verbatim %}
<ul>
{% for item in seq %}
<li>{{ item }}</li>
{% endfor %}
</ul>
{% endverbatim %}
Source: http://twig.sensiolabs.org/doc/tags/verbatim.html
For bigger blocks of templates I would suggest to move those script templates into a separate file/files (where I suppose they should be to make all more structured).
Then render templates in your twig by using source command {{ source('uploadables-js.html') }} (IMPORTANT, no 'use' or 'include').
To not litter templates with raw or verbatim tags, one can change lexar options to not conflict with client side template engines:
...
$lexer_options = [
'tag_variable' => ['{~', '~}'],
];
$lexer = new Twig_Lexer($twig, $lexer_options);
$twig->setLexer($lexer);