I have a field in a Symfony form which contains three constraints.
For one of the three constraints, if validation fails, I want to trigger a popup notice on the form once the page has reloaded. This looks beyond the scope of Twig's form_errors() function.
Is there any way of finding out if a specific constraint on a single field has failed in my Twig template? I'm struggling to find a way to access this information right now. (I'm not opposed to passing a flag to the template from my controller if necessary.)
(Might be worth adding that this is a Silex project.)
You can check form.field.vars.errors like this:
<input type="text" name="msisdn"
class="{{ form.msisdn.vars.errors|length ? 'error' : '' }}"
value="{{ form.msisdn.vars.value }}" />
The actual errors are in an array, you can loop and output them individually like this:
<span class="errorMessage">
{% for error in form.msisdn.vars.errors %}
{{ error.message }}{% if not loop.last %},{% endif %}
{% endfor %}
</span>
Related
I'm using PHP and Twig for an application in which I want to be able to have consistent form inputs across the site that are all rendered from one place in the code.
That is, I want all the form input generation markup to be in one place so that if/when I want to make a change to how the form inputs look and function across the entire site, I can change one thing in one place and have it take effect everywhere.
What's the best way to go about accomplishing this with Twig?
Thank you.
Use twig's macro
https://twig.symfony.com/doc/2.x/tags/macro.html
forms.html:
{% macro input(name, value, type, size) %}
<input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" />
{% endmacro %}
usage:
{% import "forms.html" as forms %}
<p>{{ forms.input('password', null, 'password') }}</p>
Just started using OcteberCMS and now trying to figure out how to translate with rainlab.translate plug-in partial (no, I can't use here {{ ''|_ }} for some reason).
For example, code of layout:
{% partial "footer" %}
I have 2 files in "partials" dir:
footer.htm and footer.fr.htm
but always footer.htm including, but not footer.fr.htm when I'm switch language to fr.
Or maybe is there some way to pass translated variable to partial?
{% partial "sidebar-contacts" city="Vancouver" country="Canada" %}
{% partial "sidebar-contacts" city="{{ 'Vancouver'|_ }}" country="Canada" %}
Thanks in advance.
It's very simple: just pipe variable |_ into translate plug-in like this:
{% partial "sidebar-contacts" city="Vancouver" country="Canada" %}
In file sidebar-contacts:
<div class="sidebar-contacts">
{{ city|_ }}, {{ country|_ }}
</div>
I'm building a themed view in Drupal 8 using twig. I'd like to use twig filters on the row.content variable in the views-view-unformatted.html.twig template.
It seems that row.content is an array so twig's string manipulation doesn't work. However, it prints onto the page as a string (view is just a list of taxonomy terms).
What I'd like to do is slugify the output so taxonomy terms with spaces can have valid hrefs. See the replace filter in the code below.
<ul class="nav nav-tabs" role="tablist">
{% for row in rows %}
<li role="presentation" class="{{loop.first ? 'active' : ''}}">
{{row.content}}
</li>
{% endfor %}
</ul>
This will just output <a href="#">. Does anyone know how to access the raw text value that is output during twigs interpolation?
Thanks!
I ran into this myself it was difficult because kint and dump crashes on views.
there is a quick workaround to get to the bits though, put this under {% for row in rows %} in your twig views style template.
<ol>
{% for key, value in row.content %}
<li>{{ key }}</li>
{% endfor %}
</ol>
load the page with that & gives you the keys to see, I checked them each with the following dump command, just added underneath to test.
{{ dump(row.content['#row']) }}
The above dump showed all the goods in #row, where I dug in and found the field I wanted inside _entity (may be different for you), then I wanted to replace spaces with dash and force lowercase.
Everything past row.content['#row'] is likely different for you, you'll need to dig in the array a bit with the dump command mentioned above.
Below is the line that got me what I wanted.
{{ row.content['#row']._entity.title[0].value|replace(' ', '-')|lower }}
Below is twig template example.
For filename change viewname and block-3 to your setup.
views-view-unformatted--viewname--block-3.html.twig
{% for row in rows %}
{%
set row_classes = [
default_row_class ? 'views-row',
'something',
'kint-cant',
]
%}
{# My field value unformatted #}
<!-- {{ row.content['#row']._entity.title[0].value }} -->
<section{{ row.attributes.addClass(row_classes) }} id="{{ row.content['#row']._entity.title[0].value|replace(' ', '-')|lower }}">
{{ row.content }}
</section>
{% endfor %}
Im sure there are plenty of other ways to do this, but it worked for me as a quick solution to print out views fields in the style template, which is really useful.
The Symfony 2.3 docs say that it is possible to customize global form errors (errors that appear at top of form that are not tied to a specific field).
http://symfony.com/doc/current/cookbook/form/form_customization.html#customizing-error-output
"You can also customize the error output for just one specific field type. For example, certain errors that are more global to your form (i.e. not specific to just one field) are rendered separately, usually at the top of your form..."
They go on to say that:
"To customize only the markup used for these errors, follow the same directions as above, but now call the block form_errors"
I am confused as to what they are talking about. It seems that their prior instructions already call the block "form_errors" so I am not sure what is different.
How do I customize just the global form errors (the individual form field errors should remain the same)?
The wording on that page is confusing. I had to read it a few times too, and it feels like there should be more information. The example provided shows how to check if the error is a "compound" error (for the whole form) or just an error for the individual field.
This is how my block looks:
{% block form_errors %}
{% if errors|length > 0 %}
<ul class="alert alert-warning {% if compound %}formError{% else %}formInputError{% endif %}">
{% for error in errors %}
<li>{{ error.message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endblock form_errors %}
If it's a compound form, it renders the class as formError, and if it's just for an input it renders formInputError. That let's me style them slightly different, depending on if they appear at the top of the page or above an input. You could also make them completely separate HTML if you needed.
I have a Team to which I would like to add players (objects of Player). I've set up the form "type" classes correctly. Here's the relevant part of my view:
{% for index, player in form.players %}
<div id="template" data-prototype="{{ form_widget(form.players.get('prototype')) | e }}">
<span class="title">{{ index }}</span>
{{ form_row(player.name) }}
</div>
{% endfor %}
My problem is that data-prototype attribute doesn't include the span tag; it only contains the output of {{ form_row(player.name) }}. Is there a way to include the whole content of div#template in the data-prototype attribute?
This was bugging me too. I customized a field type and even made simple form types with a reduced fieldset (for more complex objects), but it just didn't feel right. I've come up with a solution that should do the trick :)
First - I think your <div id="team" data-prototype="..."> should be outside your loop.
Next, your prototype is just a form view object, so if you pass it to a template you can render fields by hand and customize the output. Note: autoescape has no effect on included content, so use 'filter escape'.
<div id="playerFields" data-prototype="{% filter escape %}{% include 'AcmeTeamBundle:Team:prototypePlayer.html.twig' with {'form': form.players.get('prototype')} %}{% endfilter %}">
Then in your prototypePlayer.html.twig, just render each field as you normally would in a form view.
<div>
<span class="title">{{ form_label(form.name) }}</span>
{{ form_row(form.name) }}
<span class="age">{{ form_label(form.age) }}</span>
{{ form_row(form.age) }}
{# render whatever else you like from your Form/PlayerType class... #}
<div>
My template has a different data structure to your question, but it should help :)
Cheers,
Chris
Deprecation Warning:
As of Symfony 2.1, .get() is deprecated and the above will not work. Replace form.players.get('prototype') with form.players.vars.prototype to fix this in later versions of Symfony.