Reputation: 4000
In my registration form i have a checkbox "I accept the terms", and want to link the word "terms" to my terms page.
Is there a way to add a link to a form label, using a route? (preferably without injecting the container in the form)
Upvotes: 9
Views: 10690
Reputation: 684
My current Symfony v7 Registration Form.
Terms and conditions are added via the help
attribute with help_html
set to true
.
Router is injected in the controller as a Form is a service.
<?php
namespace App\Form;
use App\Entity\User;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Validator\Constraints\IsTrue;
use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Validator\Constraints\NotBlank;
class RegistrationFormType extends AbstractType
{
public function __construct(
private readonly RouterInterface $router
)
{
}
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('name', TextType::class, [
'label' => 'Name',
'attr' => [
'autofocus' => true,
'autocomplete' => 'name',
],
'constraints' => [
new NotBlank([
'message' => 'Please enter a password',
]),
],
])
->add('email', EmailType::class, [
'label' => 'Email',
'attr' => [
'autocomplete' => 'email',
],
])
->add('plainPassword', PasswordType::class, [
// instead of being set onto the object directly,
// this is read and encoded in the controller
'mapped' => false,
'label' => 'Password',
'help' => 'Your password should be at least 6 characters long.',
'attr' => [
'autocomplete' => 'new-password'
],
'constraints' => [
new NotBlank([
'message' => 'Please enter a password',
]),
new Length([
'min' => 6,
'minMessage' => 'Your password should be at least {{ limit }} characters',
// max length allowed by Symfony for security reasons
'max' => 4096,
]),
],
])
->add('agreeToTerms', CheckboxType::class, [
'mapped' => false,
'label' => 'Agree to our terms and conditions',
'help' => 'View <a href="' . $this->router->generate('app_terms') . '">terms and conditions</a>.',
'help_html' => true,
'constraints' => [
new IsTrue([
'message' => 'You should agree to our terms and conditions.',
]),
],
])
->add('submit', SubmitType::class, [
'label' => 'Continue',
'attr' => [
'data-variant' => 'primary',
'style' => 'width: 100%;'
]
]);
}
public function getBlockPrefix(): string
{
return '';
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => User::class,
]);
}
}
Upvotes: 0
Reputation: 1700
In Symfony 5.1 there are new form improvements.
HTML contents are allowed in form labels!
HTML contents are escaped by default in form labels for security reasons. The new label_html boolean option allows a form field to include HTML contents in their labels, which is useful to display icons inside buttons, links and some formatting in checkbox/radiobutton labels, etc.
// src/Form/Type/TaskType.php
namespace App\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormBuilderInterface;
class TaskType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
// ...
->add('save', SubmitType::class, [
'label' => ' Save',
'label_html' => true,
])
;
}
}
In your case you can set form label directly from template and pass the route there.
{{ form_widget(form.acceptTermsAndConditions, {
label: '<a href="' ~ path("route") ~ '">' ~ "I accept ..."|trans ~ '</a>',
label_html: true
})
}}
Upvotes: 8
Reputation: 34105
The best way is to overwrite the twig block used to render that specific label.
First, check the form fragment naming section of the docs. Then create a new block in your form template with the the appropriate name. Don't forget to tell twig to use it:
{% form_theme form _self %}
For the next step check the default form_label
block.
You'll probably only need a portion of it, something like this (I'm leaving the default block name here):
{% block form_label %}
{% spaceless %}
<label{% for attrname, attrvalue in label_attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}>
<a href="{{ path("route_for_terms") }}">{{ label|trans({}, translation_domain) }}</a>
</label>
{% endspaceless %}
{% endblock %}
Upvotes: 4
Reputation: 167
As an option, you can do so:
->add('approve', CheckboxType::class, [
'label' => 'Text part without link',
'help' => 'And <a href="/x.pdf">download it</a>',
'help_html' => true,
])
Upvotes: 3
Reputation: 27
A very simple way to do it would be
{{ form_widget(form.terms, { 'label': 'I accept the <a href="'~path('route_to_terms')~'">terms and conditions</a>' }) }}
You can also do this if you want to use translation
In your translation file for example messages.en.yml add
terms:
url: 'I accept the <a href="%url%">terms and conditions</a>'
And in your view add
{{ form_widget(form.terms, { 'label': 'terms.url'|trans({'%url%': path('route_to_terms')}) }) }}
Upvotes: -1
Reputation: 727
My solution was another:
form:
$builder
->add(
'agree_to_rules',
'checkbox',
[
'required' => true,
'label' => 'i_agree_to'
]
);
And html:
<span style="display:inline-block">
{{ form_widget(form.agree_to_rules) }}
</span>
<span style="display:inline-block">
<a href="#">rules</a>
</span>
And looks the same :)
Upvotes: 1
Reputation: 10800
As the solution above somehow didn't work for me I solved it using the solution suggested here: https://gist.github.com/marijn/4137467
OK, so here i how I did it:
{% set terms_link %}<a title="{% trans %}Read the General Terms and Conditions{% endtrans %}" href="{{ path('get_general_terms_and_conditions') }}">{% trans %}General Terms and Conditions{% endtrans %}</a>{% endset %}
{% set general_terms_and_conditions %}{{ 'I have read and accept the %general_terms_and_conditions%.'|trans({ '%general_terms_and_conditions%': terms_link })|raw }}{% endset %}
<div>
{{ form_errors(form.acceptGeneralTermsAndConditions) }}
{{ form_widget(form.acceptGeneralTermsAndConditions) }}
<label for="{{ form.acceptGeneralTermsAndConditions.vars.id }}">{{ general_terms_and_conditions|raw }}</label>
</div>
Upvotes: 6