How to handle forms that are used on multiple pages? - php

I have a form I need to use on multiple pages:
Controller
$emailForm = $this->get('form.factory')->createNamedBuilder('form', 'email_form')
->add('email', 'email')
->add('subject', 'text')
->add('body', 'textarea')
->getForm();
$request = $this->get('request');
if ($request->getMethod() == 'POST' && $request->request->has('email_form') ) {
$emailForm->bindRequest($request);
if ($emailForm->isValid()) {
// do stuff ...
$this->get('session')->setFlash('email_sent', "Woey, mail sent successfully!");
// Redirect on the same url to prevent double posts
return $this->redirect($this->generateUrl($this->getRequest()->attributes->get('_route')));
}
}
return $this->render('Bundle:Form:index.html.twig', array('email_form' => $emailForm->createView()));
Template
{% if app.session.getFlash('email_sent') %}
<p>{{ app.session.getFlash('email_sent') }}</p>
{% endif %}
<form action="{{ path(app.request.attributes.get('_route')) }}" method="post" {{ form_enctype(email_form) }}>
{{ form_widget(email_form) }}
<p><input type="submit" class="submit" value="Send" /></p>
</form>
It's really just standard Symfony2 form, almost like from tutorial.
I can't figure how can I efficiently use it on multiple pages (in multiple controller actions) without repeating myself (too much). So far I tried:
putting the logic into Base controller, which is parent for every controller where I want to have this form. There were 2 problems with this approach:
I couldn't figure how to redirect properly to the same page
I had to call method from parent in every action, which isn't really a problem, but I guess there has to be some more elegant way
rendering controller using embedded controllers in twig. However, I couldn't figure how to redirect properly.
So, what's the common approach to such forms?
Edit:
I'm looking for a no script solution.

I ended up using embedded controller on every page I needed, posting to different URL and saving cookie with referrer. Then I validate form, save cookie with results, redirect back to referrer and render results (errors, thank you message...). This seems to be the best option when you are dealing with scenarios where you have to think about disabled Javascript. You can easily disable creating of redundant cookies / flash sessions using simple conditions for cases when user is posting using AJAX.

The Symfony2 Forms tutorial addresses your scenario as well, see the Creating Form ClassesDocs Section in which "you'll learn how to build your form in a standalone class, which is recommended as your form becomes reusable" (Ibid.).

You should submit the data via an ajax post.
In the controller do your thing :p
Then render the form in the twig template, without extending layouts. (like it would be currently)
Then in any view you just replace the result: $('#formDiv').html(htmlReceivedBack);
I find it the easiest to just replace the whole html div again with the new rendered html; most likely you will show a success message or some form errors.
This way the user don't have to change pages just to send a message/feedback.

Related

How can I disable auto set value in Symfony form?

I create a form in controller:
$form = $this->createFormBuilder()
->add('test', TextType::class)
->add('submit', SubmitType::class)
->getForm();
and I have this code in my twig page:
{{ form(form, { 'attr': {'autocomplete': 'off'} }) }}
Now when I write a value for input (for example "123456") and when I submit the form and it's invalid, the page refreshes and my input value display "123456" and when I refresh page again value not change.
You have several ways to do it:
You can create a new form type and customise its rendering with a global form theme template
You can render the specific field differently
You can try to overwrite the value attribute while rendering the field (could not work on some form themes)
Read the symfony documentation on form themes to know which solution is better for your use-case or application.
Anyway, for a validation code input (as read in the comments) I suggest to you to implement a new form type entirely and handle its rendering, options and logic separately.

Populating dynamic html elements on validation failure in Laravel 5.1

In my form, I am populating state and city dropdowns using ajax.
Also, on the same form the user can add multiple employees by clicking on the "Add more button".
In both above scenarios the HTML DOM elements are generated using jquery.
I need re-build the dynamically generated elements in case the validation fails on form submit.
Can anyone please tell me a right approach for achieving the above mentioned issue.
Thanks.
Say you've generated a list of inputs dynamically by calling a js function, maybe something like
//JS
function generate(){
$("#container-abc").append("<input name=name[]>");
}
<!--HTML -->
<input name=name[] />
<input name=name[] />
Submit them and if there's validation error you will get back the values using:
//in your blade
$name = Request::old('name');
#if(count($name) > 0)
for (var i = 1; i <= {{count($name)}}; i++) {
generate();
}
#endif
you can use
return Redirect::back()->withInput();
or for more info visit https://laravel.com/docs/5.2/requests#old-input
Old Input
Laravel allows you to keep input from one request during the next
request. This feature is particularly useful for re-populating forms
after detecting validation errors. However, if you are using Laravel's
included validation services, it is unlikely you will need to manually
use these methods, as some of Laravel's built-in validation facilities
will call them automatically. Flashing Input To The Session
The flash method on the Illuminate\Http\Request instance will flash
the current input to the session so that it is available during the
user's next request to the application:
$request->flash();
You may also use the flashOnly and flashExcept methods to flash a
sub-set of the request data into the session:
$request->flashOnly(['username', 'email']);
$request->flashExcept('password');
Flash Input Into Session Then Redirect
Since you often will want to flash input in association with a
redirect to the previous page, you may easily chain input flashing
onto a redirect using the withInput method:
return redirect('form')->withInput();
return redirect('form')->withInput($request->except('password'));
Retrieving Old Data
To retrieve flashed input from the previous request, use the old
method on the Request instance. The old method provides a convenient
helper for pulling the flashed input data out of the session:
$username = $request->old('username');
Laravel also provides a global old helper function. If you are
displaying old input within a Blade template, it is more convenient to
use the old helper. If no old input exists for the given string, null
will be returned:

Symfony2 Forms GET submit field type - remove 'name' param

I'm using submit form type in my FormType class (I want it to be customized for css classes and button label).
Since it's a search, I decided to go with GET, not default POST. What I noticed in Symfony2, is that:
submit field gets a "name" parameter
and when form is submitted, one of params in url is an empty "submit" (i.e.: http://url....?phrase=searchphrase&submit)
I tried to remove auto-genarated HTML "name" attr from the "button / submit" HTML tag in controller, in form type class, and even in Twig template, e.g. by overriding "name" - nothing seems to work for Symfony2, and the name="submit" for this button is always generated.
It there a way to remove this HTML attr from submit button, or am I forced to only render whole submit button by myself, and remove it from Form Type class?
Template for the search form is very basic, nothing extraordinary for Symfony2:
{{ form_start(form) }}
<div>
{{ form_widget(form.target) }}
</div>
<div>
{{ form_widget(form.phrase) }}
{{ form_widget(form.submit) }}
</div>
{{ form_errors(form) }}
{{ form_end(form) }}
And for the form type, I use standard submit:
$builder->add('submit', 'submit', array('label' => 'search', attr(name => null) ....)
As you see, here name attr is explicilty set to null. Symfony2 generate it any way, and give it a "submit" value to this 'name' attr.
The only problem is: can I make somehow Symfony2 to NOT generate "name" attr in the HTML Button/Submit tag? If Symfony2 cannot do that, it seems that the only way is to simply remove "submity" from Form Type class, and put HTML for this button directly in the template by myself, which I'm trying to not do (but if it's not possible, I will have to).
To me, it seems like it's a problem with Symfony2. Submit type is quite new thing in forms here, and I can imagine that auto-generated "name" attr follows the same rules as other form types in Symfony2 - although it is really not needed in HTML forms!
SOLUTION: So, I ended up with rendering it all by myself, and removed it from Form Type. Still I think Symfony2 shouldn't generate 'name' for this particular tag - I saw never ever "name" attr being assigned to SUBMIT button HTML tag in any form on the web, it's obviously not needed and not desired.
I think there are three solutions:
Have a form without the submit button and create the button outside of the form. Then submit the form with JS.
Override the default twig template responsible for generating HTML content of the submit button.
Generate the HTML content by yourself and not use the name there.

Load ajax/jquery JSON array into Twig Template

I am currently building a program using Symfony2 framework and also taking advantage of the many nice new features that come with the platform such as Doctrine, Twig etc.
One of my pages requires me to load a big load of data via AJAX after pageload is complete. This is easily achieved uing JQuery/Ajax but i'd like to think that something like this would have a way of injecting ajax directly into the Twig template maybe via JSON and have it populate in a for loop.
<table>
<tr><td>header</td></tr>
{% for row in rows %}
<tr><td>{{row.data}}</td></tr>
{%endfor%}
</table>
Something like this crude example.
I did browse the docs quickly for this but there search is down and i couldn't find anything directly. A link to documentation could suffice if its what im looking for.
I think the cleanest way would be to generate your Json in the controller.
Something around:
/**
* #route("/json", name="json_generator")
*/
public function jsonAction() {
// do your for loop and build up a $jsonArray
return new Response( json_encode($jsonArray) );
}
And then test the response of this in the browser and load this with Javascript in the twig template.
Don't have the specific code right now, but from the top of my head:
$(document).ready(function() {
$.ajax({
ajax: true,
url: "{{ path('/json') }}"
});
};
Just so you get the idea. Hopefully it serves you as a base example-
There is 2 ways:
1. Make AJAX request, in controller render html and return it to the script. Then add when it is needed.
2. Make AJAX request, return JSON and build html in the script, then add ready html to your specific place.
I think better way is render html in your action and return it to your AJAX script

Laravel back button

I am trying to create a simple back button on a page. The user can arrive to this page from two different pages so I would like to know from which page he arrived. Is that possible?
In Laravel, you can do something like this: Back (assuming you're using Blade).
Laravel 4
{{ URL::previous() }}
Laravel 5+
{{ url()->previous() }}
Laravel documentation
I know this is an oldish question but I found it whilst looking for the same solution. The solution above doesn't appear to work in Laravel 4, you can however use this now:
Go Back
Hope this helps people who look for this feature in L4
(Source: https://github.com/laravel/framework/pull/501/commits)
Laravel 5.2+, back button
Back
Indeed using {{ URL:previous() }} do work, but if you're using a same named route to display multiple views, it will take you back to the first endpoint of this route.
In my case, I have a named route, which based on a parameter selected by the user, can render 3 different views. Of course, I have a default case for the first enter in this route, when the user doesn't selected any option yet.
When I use URL:previous(), Laravel take me back to the default view, even if the user has selected some other option. Only using javascript inside the button I accomplished to be returned to the correct view:
Voltar
I'm tested this on Laravel 5.3, just for clarification.
The following is a complete Blade (the templating engine Laravel uses) solution:
{!! link_to(URL::previous(), 'Cancel', ['class' => 'btn btn-default']) !!}
The options array with the class is optional, in this case it specifies the styling for a Bootstrap 3 button.
On 5.1 I could only get this to work.
Back
You can use javascript for this provblem.
It's retrieve link from browser history.
<script>
function goBack() {
window.history.back();
}
</script>
<button onclick="goBack()">Go Back</button>
One of the below solve your problem
URL::previous()
URL::back()
other
URL::current()
You can use {{ URL::previous() }}
But it not perfect UX.
For example, when you press F5 button and click again to Back Button with {{ URL::previous() }} you will stay in.
A good way is using {{ route('page.edit', $item->id) }} it always true page you wanna to redirect.
<i class="fa fa-angle-left"></i> Continue Shopping
This worked in Laravel 5.8

Categories