Symfony2 - display form error in bootstrap tooltip - forms

I would like to display form error message inside bootstrap tooltip.
<div class="btn-upload" data-toggle="tooltip" data-html="true" data-title="{% if document.documentFile.vars.errors|length > 0 %}<span class='text-danger'>{{ form_errors(document.documentFile) }}</span>{% endif %}">
It should display form error inside tooltip on icon.
But message is displayed like this:
Now if I change {{ form_errors(document.documentFile) }} to "TEST MESSAGE":
So the problem is form error rendering inside tooltip. Any ideas how to fix it?

The {{ form_errors(document.documentFile) }} renders HTML with " that breaks your div.
Consider doing this :
<div class="btn-upload" data-toggle="tooltip" data-html="true" id="error-tooltip">
<script type="text/html" id="form-error">
{% if document.documentFile.vars.errors|length > 0 %}
<span class='text-danger'>{{ form_errors(document.documentFile) }}</span>
{% endif %}
</script>
<!-- ... -->
</div>
And, in your JS :
$('#error-tooltip').data('tooltip', $('#form-error').html());

I finally figured out a simplier way to achieve it by foreaching errors of document.documentFile.vars.errors. A little bit similar way to Favian's answer but without rewriting a block.
<div class="btn-upload" data-toggle="tooltip"
{% if document.documentFile.vars.errors|length > 0 %}
data-html="true"
data-title="<span class='text-danger'>
{% for error in document.documentFile.vars.errors %}
{{ error.message }}
{% endfor %}
</span>"
{% endif %}
>
Works just fine!

By default, the errors are rendered inside an unordered list:
<ul>
<li>The file is to large bla bla bla</li>
</ul>
To override how errors are rendered for all fields, simply copy, paste and customize the form_errors fragment.
<div class="btn-upload" data-toggle="tooltip" data-html="true" data-title="{% if document.documentFile.vars.errors|length > 0 %}<span class='text-danger'>
{% block form_errors %}
{% spaceless %}
{% if errors|length > 0 %}
{% for error in document.documentFile %}
{{ error.message }}
{% endfor %}
{% endif %}
{% endspaceless %}
{% endblock form_errors %}
</span>{% endif %}">
</div>

Related

Shopify linking product using SEO handle coding

I followed the directions for the second way to tag a product to a blog
This is the website I used https://happypoints.io/shopify-add-products-to-blog-post-c2-stt-66/ This is the code that was entered {% assign my_description = article.content | split: '=== split content ===' %}
{% assign my_description_size = my_description.size | minus: 2 %}
{{ my_description | first}}
<div class="show-product-list">
{% if article.tags.size > 0 %}
{% for tag in article.tags %}
{% paginate collections.all.products by 100 %}
{%- for product in collections.all.products -%}
{% if product.handle == tag %}
<div class="product_item">
{% include 'product-card-list' %}
</div>
{% endif %}
{%- endfor -%}
{% endpaginate %}
{% endfor %}
{% endif %}
</div>
{{ my_description | last}}
after following all the directions I received an error message saying
Liquid error (sections/article-template.liquid line 42): Could not find asset snippets/product-card-list.liquid
I am not sure why the product wont link to the blog using the seo handle. I have copied and pasted this code correctly and still getting this error
Collection code:
{% if collection.title == blank %}
{% assign collection_image = blank %}
{% elsif collection.image %}
{% assign collection_image = collection.image %}
{% else %}
{% assign collection_image = collection.products.first.featured_media.preview_image %}
{% endif %}
{% unless collection.title == blank %}
{% include 'card-image', type: collection_image, grid_style: grid_style %}
{% else %}
<div class="card__image-wrapper">
{% capture current %}{% cycle 1, 2, 3, 4, 5, 6 %}{% endcapture %}
{{ 'collection-' | append: current | placeholder_svg_tag: 'placeholder-svg' }}
</div>
{% endunless %}
<div class="card__info">
<h3 class="card__name h4">{% if collection.title != blank %}{{ collection.title }}{% else %}{{ 'homepage.onboarding.collection_title' | t }}{% endif %}</h3>
{% if section.settings.show_description and collection.description != blank %}
<div class="rte card__description{% if width == '2' %} card__description--padding{% endif %}">
{{ collection.description | strip_html | truncatewords: 15 }}
</div>
{% endif %}
</div>
You have correctly copy/pasted the code.
The problem is that your theme does not have a file named "product-card-list" in the snippets folder.
This is the file which contains code for the product tiles on the collection pages and the name for this file might differ in the theme that you're using.
You will need to find out the correct file name and replace "product-card-list" with that.
Can help you further if you share the code in your collection.liquid file.

How can I show all errors in Twig?

I create a form in Symfony 5 and when validation is wrong I want if errors are true, show all errors in one like this:
Errors:
error 1
error 2
error 3
...
I use :
{% if form_errors(form)|length %}
<div>Errors:</div>
{{ form_errors(form) }}
{% endif %}
but not work.
How can I do this in Twig?
You can use this in your codes:
{% if not form.vars.valid %}
<div>Errors:</div>
<ul>
{% for error in form.vars.errors.form.getErrors(true) %}
<li>{{ error.message }}</li>
{% endfor %}
</ul>
{% endif %}
You display all errors using below
{#
If the form is not valid then :
Note: in this case the form variable is : form
#}
{% if not form.vars.valid %}
<ul>
{# Loop through every form item #}
{% for child in form.children %}
{# Display the errors of the form item #}
{%for error in child.vars.errors%}
<li>{{error.message}}</li>
{%endfor%}
{%endfor%}
</ul>
{%endif%}

IvoryCKEditorBundle Symfony: How to use "ckeditor_widget" from IvoryCKEditorBundle TWIG template in my OWN redefined TWIG template

I've implemented IvoryCKEditorBundle in my SYMFONY 3.2 project.
I followed the guidelines from here and had an overview of the doc on the official Symfony site.
Now I see the following files exits in the IvoryCKEditorBundle directory:
[my
project]\vendor\egoloen\ckeditor-bundle\Resources\views\Form\ckeditor_widget.html.twig
[my
project]\vendor\egoloen\ckeditor-bundle\Twig\CKEditorExtension.php
And [my
project]\vendor\egoloen\ckeditor-bundle\Resources\views\Form\ckeditor_widget.html.twig defines {% block ckeditor_widget %}.
In my projet I have redefined my own template to render a form, using all the tricks given in the official doc. And under [my project]\src\MyBundle\Resources\views I have a file input_inline_template.html.twig which looks like that:
{% extends 'form_div_layout.html.twig' %}
{% use 'CKEditorBundle:Form:ckeditor_widget.html.twig' %}
{% block form_row %}
<div class='col-12' id={{ id ~ '_div_row_id'}}>
{% block form_label %}
<div class='col-4' id={{ id ~ '_div_label_id' }}>
{{ parent() }}
</div>
{% endblock %}
{% if form.vars.block_prefixes.2 == "textarea" %}
{% if (form.vars.block_prefixes.3 is defined) and (form.vars.block_prefixes.3 == "ckeditor") %}
{% block ckeditor_widget %}
<div class='col-8'>
{{ parent() }}
</div>
{% endblock %}
{% else %}
{% block textarea_widget %}
<div class='col-8'>
{{ parent() }}
</div>
{% endblock %}
{% endif %}
{% endif %}
</div>
{% endblock %}
This does not work. It tells me that it cannot find the ckeditor_widget if I don't have the line {% use 'CKEditorBundle:Form:ckeditor_widget.html.twig' %} it throws the error:
Block "ckeditor_widget" on template "form_div_layout.html.twig" does not exist in "form_div_layout.html.twig".
And when the line {% use 'CKEditorBundle:Form:ckeditor_widget.html.twig' %} is implemented, it throws an error that is:
Unable to find template "CKEditorBundle:Form:ckeditor_widget.html.twig"
It tells me it looks for CKEditorBundle:Form:ckeditor_widget.html.twig in:
[my_symf_project]\app/Resources/views, [my_symf_project]\vendor\symfony\symfony\src\Symfony\Bridge\Twig/Resources/views/Form, [my_symf_project]\vendor\knplabs\knp-menu\src\Knp\Menu/Resources/views.
I don't know how to configure in [my project]\app\config\config.yml that it should look in [my project]\vendor\egoloen\ckeditor-bundle\Resources\views\Form\ to find ckeditor_widget.html.twig.
I found a hint here.
In [my project]\src\MyBundle\Resources\views\input_inline_template.html.twig, I've replaced: {% use 'CKEditorBundle:Form:ckeditor_widget.html.twig' %} with: {% use 'IvoryCKEditorBundle:Form:ckeditor_widget.html.twig' %}.
It fixed it.

How is symfony form rendered in the view

I was sure I understand this process, but when I dug deeper I saw I am wrong ;(
Let's take simple form, please notice that this form contains 3 fields
$form = $this->createFormBuilder($defaultData, ['csrf_protection' => false])
->add('email', 'email')
->add('name', 'text')
->add('message', 'textarea')
->getForm()
->createView();
which is rendered as
{{ form(form, {'attr': {'novalidate': 'novalidate'}}) }}
into
Built in "form" block from vendor\symfony\symfony\src\Symfony\Bridge\Twig\Resources\views\Form\form_div_layout.html.twig looks like:
{% block form %}
{% spaceless %}
{{ form_start(form) }}
{{ form_widget(form) }}
{{ form_end(form) }}
{% endspaceless %}
{% endblock form %}
and form_widget(form)
{% block form_widget %}
{% spaceless %}
{% if compound %}
{{ block('form_widget_compound') }}
{% else %}
{{ block('form_widget_simple') }}
{% endif %}
{% endspaceless %}
{% endblock form_widget %}
{% block form_widget_simple %}
{% spaceless %}
{% set type = type|default('text') %}
<input type="{{ type }}" {{ block('widget_attributes') }} {% if value is not empty %}value="{{ value }}" {% endif %}/>
{% endspaceless %}
{% endblock form_widget_simple %}
Let's modify form and form_widget a bit:
{% block form %}
{% spaceless %}
{{ form_start(form) }}
-form_widget before-
{{ form_widget(form) }}
-form_widget after-
{{ form_end(form) }}
{% endspaceless %}
{% endblock form %}
{% block form_widget %}
{% spaceless %}
- form_widget call -
{% if compound %}
- form_widget compound-
{{ block('form_widget_compound') }}
{% else %}
- form_widget simple-
{{ block('form_widget_simple') }}
{% endif %}
{% endspaceless %}
{% endblock form_widget %}
then as an output I got (listing 5):
<form name="form" method="post" action="" novalidate="novalidate">
-form_widget before-
- form_widget call -
- form_widget compound-
<div id="form" novalidate="novalidate">
<div>
<label for="form_email" class="required">Email</label>
<input type="email" id="form_email" name="form[email]" required="required" />
</div>
<div>
<label for="form_name" class="required">Name</label>
- form_widget call -
- form_widget simple-
<input type="text" id="form_name" name="form[name]" required="required" />
</div>
<div>
<label for="form_message" class="required">Message</label>
<textarea id="form_message" name="form[message]" required="required">Type your message here</textarea>
</div>
</div>
-form_widget after-
</form>
we can easly notcie the flow
form -> form_widget (input parameter is the whole form) -> form_widget_compound -> form_rows (iterates form elements into next function) -> form_row -> form_widget (this call form element is passed as parameter)
so here is the time for question, if form_widget is called 4 times (or more), once for form, 3 times for fields then why in listing 5 'form_widget call' text appears only 2 times?
or other words how email and message were rendered?
The form theming in SF2 uses inheritance. That means that if blocks named email_widget and textarea_widget are defined, neither your e-mail nor your textarea fields will use form_widget. They will rather respectively use their own widget blocks: email_widget and textarea_widget.
Well, in form_div_layout.twig, these two widget blocks are defined. Thus form_widget is not called for 2 of your fields. Thus your message is displayed 2 times instead of 4.
If you want to customize the rendering of these fields, you will have to create your own block definitions email_widget and textarea_widget in your custom form theme file.
Edit:
The default form theme files are defined under Symfony\Bridge\Twig\Resources\views\Form. The default file used is form_div_layout.html.twig.
Although the inheritance logic itself is indeed in the PHP code of the TWIG bridge, it does not define which block inherit from which other block.
Inheritance is actually defined in your FormType classes. Each form type class sports a getParent() method that return the name of the form from which it inherits. The name of a form type is the result of the method getName() of its associated form type class. For instance, with a built-in example, Symfony\Component\Form\Extension\Core\Type\TextareaType:
Textarea >> Text >> Field >> Form
All you have to do is to look for the methods getParent() and getName(). Thus, by default, when rendering the textarea row, Twig will search the block textarea_row, text_row, field_row and finally form_row (the base default row). The first of these blocks that is defined in your form theme is rendered.
The definition of the blocks themselves happen in the form theme files.

Symfony2: add class to every select

I'm trying to customize Symfony2 form rendering to add a class to every select that is generated.
I thought that having a custom form_div_layout.html.twig with:
{% block choice_widget_collapsed %}
{% spaceless %}
<select class='myclass' {{ block('widget_attributes') }}{% if multiple %} multiple="multiple"{% endif %}>
{% if empty_value is not none %}
<option value="">{{ empty_value|trans({}, translation_domain) }}</option>
{% endif %}
{% if preferred_choices|length > 0 %}
{% set options = preferred_choices %}
{{ block('choice_widget_options') }}
{% if choices|length > 0 and separator is not none %}
<option disabled="disabled">{{ separator }}</option>
{% endif %}
{% endif %}
{% set options = choices %}
{{ block('choice_widget_options') }}
</select>
{% endspaceless %}
{% endblock choice_widget_collapsed %}
and using it with
{% form_theme form 'YOPYourOwnPoetBundle:Form:form_div_layout.html.twig' %}
would do the trick.
However, the class 'myclass' isn't added to the select.
What am I doing wrong?
You should first make sure the theme file you're trying to use has the same name as the name you're using in the form_theme expression and that the file really is there. I can't remember off top of my head whether Twig throws an exception or not in case these do not match.
In addition, you might be accidentally passing a class attribute either when building a form or rendering it. What happens is that your element now has two class attributes.
A workaround is to actually add your new class to the collection of existing ones.
{% block choice_widget_collapsed %}
{% spaceless %}
{% set label_attr = label_attr|merge({class: label_attr.class|default('') ~ ' required'}) %}
{% set attr = attr|merge({class: (attr.class|default('') ~ ' myclass')|trim}) %}
<select {{ block('widget_attributes') }}{% if multiple %} multiple="multiple"{% endif %}>
{# ... #}
</select>
{% endspaceless %}
{% endblock choice_widget_collapsed %}
This allows you to add any optional class you might need for specific elements later on.
EDIT
Looking at the Sf2 Github repsitory it seems that the theme file has been recently changed. In versions 2.0.* you should be overriding choice_widget, in versions 2.1.* the correct block is choice_widget_collapsed.
I suppose you should either change the form theme line to:
{% form_theme form 'YOPYourOwnPoetBundle:Form:form_div_layout.html.twig' %}
or you need to change the name of your twig file into fields.html.twig
Both have to match.