i have a simple form and i want display another form after submitting in the same template twig
mycontroller:
/**
* #Route("/admin/client/modifier", name="modifier")
* #Method({"GET","POST"})
*/
public function modifierAction(Request $request)
{
$form=$this->createFormBuilder()
->add('raisonSocial', TextType::class)
->add('Rechrecher', SubmitType::class)
->getForm();
if($form->isSubmitted() && $form->isValid()){
} ;
return $this->render('myTemplate/Clients/modifierClient.html.twig');
}
You have to adapt your answer to the correct way. I do not remember exactly the correct $request->request->get syntax so check the documentation.
Anyway... I guess you can achieve this by using a render controller inside your twig based on some parameters that come from the post/get of your form submission or via ajax (but you already said you don't know how to do this via ajax).
So let's say you search "test" you should have inside your $request->request->get your parameter test.
you should to something like this in your twig file:
your div where you want to have the form displayed
<div>
{% if app.request.get('your_key') == 'test' %}
{{ render(controller(''AppBundle:Article:recentArticles'')) }}
{% endif %}
</div>
This means that you will need to create yourself a new action in ArticleController called recentArticles where you will have your new form.
You can find more details about this on the symfony documentation here:
https://symfony.com/doc/current/templating/embedding_controllers.html
Related
I want to create a search bar in my navbar, so one can simply search for a user on my page.
I have a base.html.twig, where the navbar, the header, the footer, and more are defined, to make all my pages have the same layout. I have then for every subpage e.g. a profile.html.twig, which defines the actual content of the page.
I wanted to include a search line in the navbar, so I read about embedding controllers, which seemed like a perfect idea for me. So I created a SearchForm class, which builds a form with the FormBuilderInterface like so:
class SearchForm extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('searched_name')
;
}
}
Then I created a SearchController, which would contain the logic for what should happen when the search form would be submitted and should return a render of the form.
class SearchController extends AbstractController
{
/**
* #param Request $request
*
* #return Response|RedirectResponse
*
* #Route("/search", name="search", methods={"GET","POST"})
*/
public function renderSearch(Request $request) {
$form = $this->createForm(SearchForm::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
return $this->redirectToRoute('ping');
//TODO: Implement search logic
}
return $this->render('searchForm.html.twig', [
'form' => $form->createView()
]);
}
}
I thought, that I now could simply go ahead and let the search form be rendered in the base.html.twig:
<div class="topnav" id="navbar">
Startseite
Übersicht
Über uns
{{ render(url('search')) }}
<a href="/profile" style="float:right">
{% if app.user %}
{{ app.user.username }}
{% else %}
Mein Profil
{% endif %}
</a>
</div>
It actually does get rendered, but the problem is, that as soon as I press Enter to submit the form with the search input, the POST request is not sent to the searchController, but to whichever controller is responsible for handling, let's say, the profile page.
I guess it has to do something with the entire site being rendered there, since I just inherit the base.html.twig in all of my other pages, so the submit requests are sent there. I tested this by calling the search route directly, and that made it work completely fine.
How can I make this formwork on every site without having to reimplement the search logic in every single controller? (That's what this base is made for, after all...)
First of all you could (of course) set the action attribute of the form. Follow this link to find out how: https://symfony.com/doc/4.2/form/action_method.html
But since you show your form on every single page on your website you should ask yourself if you want to redirect the user to an other page after form submit. The answer could be yes or could be no but if it is no then you have the opportunity to use an AJAX submit.
I have created a custom form type - RecaptchaType. I added it into many forms using $builder->add('recaptcha', RecaptchaType::class). For view I have created a macro, so in twig I render it as follows {{ forms.recaptcha(form.recaptcha) }}.
But now I want to display recaptcha only for users who are not logged in. In twig macro I can simple add if condition. But how can I achieve not adding (or removing) recaptcha input in form type if I want to edit only RecaptchaType and don't want to touch form types, which are using this.
I had two ideas, but neither of them did work.
In RecaptchaType use function buildForm and do $builder->remove('recaptcha') when condition is met (user is logged in)
Pass option 'render' to $resolver->setDefaults(), access it in form and depend on value do ->add or not. But I can't access the value.
How would you do that? I can add code example if needed.
TL;DR; To remove a form type conditionally encapsulating this logic within itself, you can do the follows:
RecaptchaType:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
if ($this->isAuthenticated()) {
$form = $event->getForm();
$form->getParent()->remove($form->getName());
}
});
}
Now, if you are customizing the form theme make sure to check the existence of the field before render it:
{% if form.recaptcha is defined %}
{{ forms.recaptcha(form.recaptcha) }}
{% endif %}
It should work as long as your RecaptchaType is embedded into another form.
I try to render a few fields in my form, not all, but twig always render all fields. It is my twig code:
{{ form_start(form) }}
{{form_widget(form.subject)}}
{{form_widget(form.name)}}
{{form_widget(form.parent,{'value' : ''})}}
{{form_widget(form.save)}}
{{ form_end(form) }}
Set type for field you don't want visible to hidden. your form type would look something like this:
class ConfigurationFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('email', HiddenType::class)
// more fields
}
// other configurations
}
The form_end function renders the elements that have not been rendered yet. Read here: http://symfony.com/doc/current/reference/forms/twig_reference.html#form-end-view-variables.
This helper also outputs form_rest() unless you set render_rest to
false
You can disable that behaviour as you can see in the docs.
Anyway you should render all fields for validation to work, for example, and for security reasons (as it will add validation for CSRF automatically).
I've created a new form type for a simple one field newsletter signup form. What's the best way to embed this across different pages, multiple times on my site?
I could create a new instance of this form with a different name in every controller to show in my twig templates, but this seems a little messy. Ideally I'd like to be able to add more than one form on a page, and add them easily to a template.
I've tried {% render controller('MyBundle:EmailSubscribe:subscribe') %} but this doesn't work with multiple inserts, and I'm sure there's a better way anyway. Any ideas?
May be with Twig extension? This kind of task is the next one in my current project (e-commerce project where I need to display multiple addToCart forms on category pages), I'm also planning to do this with Twig function, for example (I did'nt test it yet):
private $formFactory;
public function __construct(FormFactoryInterface $formFactory)
{
$this->formFactory = $formFactory;
}
public function getFunctions() {
return [
new \Twig_SimpleFunction('newsletter_form', [$this, 'getNewsletterForm']),
];
}
public function getNewsletterForm()
{
$formFactory = $this->formFactory;
$form = $formFactory->create('my_form_alias', null_OR_data);
return $form->createView();
}
and use it in template as newsletter_form
Im a fan of xurshid29's Answer
What I do is simplay render the controller like your answer suggests. But that causes only one form to get processed, and leaves the unprocessed forms with errors like Cannot extra fields and so forth.
The Solution:
Pass the request from the original controller.
In Controller
function myAction(Request $request){
$this->render('path:to:template.html.twig', array('request'=>$request));
}
And In my Twig Template I simply pass the request to that controller.
{% render(controller('path:to:controller',{request:request} %}
And now you can create a base template for that form and include it in any template all across the site. This was especially useful for me with FOSUserBundle!
There may be some kind of twig function app.request ? I've been too lazy to try look it up. But in that case you don't have to pass request from original controller.
Extra tips on this subject
What I like to do that allows me to insert my forms anywhere for rapid dev is to build a controller/template for each form, like a "Join our Mailing List" or something.
Controller - The goal of this controller is to process the form and output "success" or show the form.
public function emailSubscribeFormAction(Request $request){
$email = new Email() //Presumed Entity for form
$form = /* Create Form Here */->getForm();
$form->handleRequest($request);
if($form->isValid()){
$form = "success"; //Change form into a string
}
$this->render('path:to:email-form.html.twig', array(
'form'=>($form=="success") ? $form : $form->createView();, // Either pass success or the form view
'request'=>$request
}
Twig email-form.html.twig
{% if form == "success" %}
<h4 id="form-success">Thanks for joining!</h4>
<script>
window.location = "#form-success" /*Bring the user back to the success message*/
</script>
{% else %}
<h4>Come on, Join Our Mailing List!</h4>
{{ form(form) }}
{% endif %}
Now you can render that controller anywhere and not have to worry about another thing about it.
Can work with multiple forms but I may have read there are drawbacks to rendering controllers like this?
If I understood your problem correctly you want to embed the same form multiple times in a page and this is to be done for multiple pages. So lets say that for page_1 you want to embed the subscribe_form N times you can obviously create a form and add this form type N times like this:
$form = $this->createFormBuilder()
->add('subscribe1',new SubscribeType())
->add('subscribe2',new SubscribeType())
...
->add('subscribeN',new SubscribeType())
->getForm();
So you can also do this in a for loop like this:
$form = $this->createFormBuilder();
for ($i = 1; $i<N+1; $i++){
$formName = 'subscribe'.$i;
$form->add($formName,new SubscribeType());
}
$form->getForm();
Now you can include this code in a controller as you said and pass the variable N as argument in each of your twig templates. Moreover, you can do this through javascript especially if you want to add these forms(SubscribeType) dynamically using allow_add option in your form. Documentation about this is here: http://symfony.com/doc/current/cookbook/form/form_collections.html#allowing-new-tags-with-the-prototype.
Hope that helps otherwise inform me if I misunderstood your problem.
I've just started a new Symfony2 project where I've used the generate:doctrine:crud to quickly scale out a few views, forms, etc.
The generated form code is just:
{{ form(form) }} but includes a generic create or delete button. I was wondering how I could add a class to these generic buttons or modify them in any way since it's just encompassed in {{ form(form) }}?
For reference I'm using Twitter Bootstrap to quickly apply some styles so I don't want to change the css based on the submit button.
Thanks!
You can specify CSS classes in the form builder class to avoid filling your Twig template with html even for rendering the form individually.
When you call {{ form(form) }} you are using a helper to simplify your code so you don't have to call form_widget for each one of your fields, but doing so you can't control the exact display in the template. To do it you have to specify the class that will be applied to the field.
In the WhateverType.php file, inside the Forms folder, you have the form builder. There you should have something like:
$builder
->add('text')
->add('whatever')
There you have to add the classes:
$builder
->add('text', 'attr'=> array('class'=>'btn')
->add('whatever')
Then, when your form is displayed in the template, it will apply the classes that you specified in the builder.
After following dmnptr's answer (breaking form into parts), you can pass an array of arguments to each form / form_row / form_label etc by:
{{ form(form, { 'attr': { 'class': 'your-css-class-1 your-css-class-2' } } ) }}
The attr param sets attributes for the item, so the above would produce:
<form class="your-css-class-1 your-css-class-2" ...
You are going to have to render each filed by hand and add necessary classes to elements in your TWIG. Read on how to do it in the official docs - http://symfony.com/doc/current/book/forms.html#rendering-each-field-by-hand