I have made a form created after an Ajax request (after the first form (Test1Type) is submitted)
public function indexAction(Request $request): Response
{
$form = $this->createForm(Test1Type::class);
$form->handleRequest($request);
if ($request->isXmlHttpRequest()) {
$form = $this->createForm(Test2Type::class);
return new Response($this->renderView('test/_results.html.twig', [
'form' => $form->createView(),
]));
}
return $this->render('test/index.html.twig', [
'form' => $form->createView(),
]);
}
Then I want to submit, validate and get the datas from this Test2Type in another method
public function confirmAction(Request $request): Response
{
dump($form->getData());
return $this->render('test/confirm.html.twig', [
]);
}
But I don't have acces to my form variable and I will not re-use $form = $this->createForm(Test2Type::class);...
I think this is possible but I really don't have any clues to made this work...
Do you have some ideas ?
It's not possible, you must create $form variable before using it for submittion and validation. To avoid duplicate code on create Test2Type form, you should redirect to confirmAction in indexAction after the form submitted and valid.
public function indexAction(Request $request)
{
$form = $this->createForm(Test1Type::class)->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
return $this->redirectToRoute('confirm.action.route_name');
}
return $this->render('test/index.html.twig', [
'form' => $form->createView(),
]);
}
public function confirmAction(Request $request)
{
$form = $this->createForm(Test2Type::class)->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
return $this->render('test/confirm.html.twig', [
'data' => $form->getData()
]);
}
return $this->render('test/_results.html.twig', [
'form' => $form->createView(),
]);
}
You should add another action in your controller for the ajax request with another route!!
This is better readable code and works better with the history button of your browser. (less cache problems) furthermore you can of course simply change the 'action' attribute of the HTML <form> element. Follow this link to read how: http://symfony.com/doc/current/form/action_method.html
Related
I have built a website using php and the zend framework. In one of the pages I have a zend form and a table. The user can fill in the form, click the search button(page refresh occurs) and then get the corresponding results in the table.
What I am trying to do is to implement the same functionality using Ajax so the page won't have to refresh or ask for re-submission when reloaded.
From my controller I pass the data I want to display to view.phtml.
When the page first opens all the data from database gets displayed in the table. Somehow after the user clicks search :
the ajax post data should be retrieved in the controller
compared to the rest of the data to see if there are any matches
return the data matched
public function searchAction(): ViewModel
{
$persons = $this->personsService->getAllPersons();
$form = $this->personsForm;
if ($this->getRequest()->isPost()) {
$formData = $this->params()->fromPost();
$form->setData($formData);
if ($form->isValid()) {
$validFilteredData = $form->getData();
$persons = $this->personsService->getPersonsAfterSearch($validFilteredData);
}
}
return new ViewModel([
'persons' => $persons,
'form' => $form,
]);
}
I would like any suggestions on how to implement ajax since I am a beginner in web development and I don't experience working with ajax.
Thanks in advance.
Before you do this:
return new ViewModel([
'persons' => $persons,
'form' => $form,
]);
Add this:
if ($this->getRequest()->isXmlHttpRequest()) {
return new \Zend\View\Model\JsonModel(
[
'persons' => $persons,
'form' => $form,
]
);
}
Note: you've tagged "zend-framework" but mentioned "zend3". Above solution works for ZF2 and ZF3, don't know about ZF1.
Update due to comments:
Full function would be:
public function searchAction() : ViewModel
{
$persons = $this->personsService->getAllPersons();
$form = $this->personsForm;
if ($this->getRequest()->isPost()) {
$formData = $this->params()->fromPost();
$form->setData($formData);
if ($form->isValid()) {
$validFilteredData = $form->getData();
$persons = $this->personsService->getPersonsAfterSearch($validFilteredData);
}
}
$data = [
'persons' => $persons,
'form' => $form,
];
// AJAX response
if ($this->getRequest()->isXmlHttpRequest()) {
return new \Zend\View\Model\JsonModel($data);
}
return $data; // No need to return "new ViewModel", handled via ZF magic
}
I have a search form that works with the method POST, but the method POST doesn't display the requested data in the url.
With method POST the url look like this:
/search_flight
with the method GET no results found, the url look like this:
/search_flight?from=Cape+Town%2C+International+CPT&to=Johannesburg%2C+O.R.+Tambo+International+JNB&departuredate=2016%2F01%2F08&arrivaldate=2016%2F10%2F04&price=57.5%2C1000
I also noticed that with the method GET the data is reset in each input of the form.
routing.yml
searchFlight:
path: /search_flight
defaults: { _controller: FLYBookingsBundle:Post:searchtabflightResult }
requirements:
_method: GET|POST
controller
This method send the requested data to the method searchtabflightResultAction that will handle the query.
public function searchtabflightAction()
{
//$form = $this->createForm(new SearchflightType(),null, array('action' => $this->generateUrl('searchFlight'),'method' => 'GET',));
$form = $this->get('form.factory')->createNamed(null, new SearchflightType());
return $this->render('FLYBookingsBundle:Post:searchtabflight.html.twig', array(
'form' => $form->createView(),
));
}
.
<form action="{{ path ('searchFlight') }}" method="GET">
{# here I have my forms #}
</form>
.
public function searchtabflightResultAction(Request $request)
{
//$form = $this->createForm(new SearchflightType());
$form = $this->get('form.factory')->createNamed(null, new SearchflightType());
$form->handleRequest($request);
$em = $this->getDoctrine()->getManager();
$airport1 = $form["to"]->getData();
$airport = $form["from"]->getData();
$departureDateObj = $form["departuredate"]->getData();
$arrivalDateObj = $form["arrivaldate"]->getData();
$price = $form["price"]->getData();
$entities = $em->getRepository('FLYBookingsBundle:Post')->searchflight($airport1,$airport,$departureDateObj,$arrivalDateObj,$price);
return $this->render('FLYBookingsBundle:Post:searchtabflightResult.html.twig', array(
'entities' => $entities,
'form' => $form->createView(),
));
}
How can I make my search filter works with method get ?
Everything should be done within two actions, the basic concept is:
SearchFlightType has with/wo price option:
class SearchFlightType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('from', FormType\TextType::class)
->add('to', FormType\TextType::class)
->add('departuredate', FormType\TextType::class)
->add('arrivaldate', FormType\TextType::class);
if ($options['price']) {
$builder->add( 'price', FormType\TextType::class );
}
$builder
->add('submit', FormType\SubmitType::class);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'price' => false,
));
}
}
Controller.php
class PostController extends Controller
{
/**
* #Route("/index", name="index")
*/
public function indexAction(Request $request)
{
$defaultData = array();
$form = $this->createForm(SearchFlightType::class, $defaultData, array(
// action is set to the specific route, so the form will
// redirect it's submission there
'action' => $this->generateUrl('search_flight_result'),
// method is set to desired GET, so the data will be send
//via URL params
'method' => 'GET',
));
return $this->render('Post/searchtabflight.html.twig', array(
'form' => $form->createView(),
));
}
/**
* #Route("/search_flight_result", name="search_flight_result")
*/
public function searchTabFlightResultAction(Request $request)
{
$defaultData = array();
$entities = null;
$form = $this->createForm(SearchFlightType::class, $defaultData, array(
// again GET method for data via URL params
'method' => 'GET',
// option for price form field present
'price' => true,
));
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// get data from form
$data = $form->getData();
// process the data and get result
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('FLYBookingsBundle:Post')->searchflight($data['from'], $data['to'], ...);
}
return $this->render('Post/searchtabflight.html.twig', array(
'form' => $form->createView(),
// present the result
'entities' => $entites,
));
}
}
What I want to do is quite simple. I have a first form. When this form is submitted, I have another form. When this second form is submitted, I want execute somes actions.
So here is my controller simplified:
$app->post('/path', function(Request $request) use ($app) {
$app['request'] = $request;
$token = $app['security.token_storage']->getToken();
if (null !== $token) {
$user = $token->getUser();
// First form
$form = $app['form.factory']->createBuilder(FormType::class)
->add('field_form1', TextType::class, [
'required' => true,
])
->getForm();
// Second form
$formcb = $app['form.factory']->createBuilder(FormType::class)
->add('field_form2', TextType::class, [
'required' => true,
])
->getForm();
// When second form is submitted
$formcb->handleRequest($request);
if($formcb->isSubmitted() && $formcb->isValid()) {
// isValid is never true
$data = $formcb->getData();
}
// When first form is submitted
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()) {
$data = $form->getData();
switch ($data["paiementType"]) {
[...]
case 'mycase':
// Render of the second form
return $app['twig']->render('page2.twig', [
'form' => $formcb->createView(),
]);
default: break;
}
}
// Render of the first form
return $app['twig']->render('page1.twig', [
'form' => $form->createView(),
]);
}
})->bind('path');
But,
No problems for the first form, it works well.
The second form seems to have already been validated when it is render, because the fields errors message are display on the form.
When I submit the second form, I never enter in the if($formcb->isSubmitted() && $formcb->isValid()) { clause, because isValid is never true... However, the form is submitted...
So I don't know what is wrong, maybe it is not the good way to render a form behind another form...
I'm making a REST API that should validate data entry from the user, to achieve that, I made a Request class that has the rules function that it should do the validations.
Request class
class StoreUpdateQuestionRequest extends Request {
public function authorize() {
return true;
}
public function rules() {
$method = $this->method();
$rules = [
'question' => 'required|min:10|max:140',
'active' => 'boolean',
];
return $method !== 'GET' || $method !== 'DELETE' ? $rules : [];
}
}
So, in the controller, when I try to run an endpoint which it fires the validations, it does work, it fails when it's has to, but it doesn't show me the errors as I expect, even though I defined the error messages in the messages function contained in the Request class, instead of showing me that errors, it redirects me to a location. Which sometimes is the result of a request I made before or it runs the / route, weird.
Controller function
public function store(StoreUpdateQuestionRequest $request) {
$question = new Question;
$question->question = $request->question;
$question->active = $request->active;
if($question->save()) {
$result = [
'message' => 'A question has been added!',
'question' => $question,
];
return response()->json($result, 201);
}
}
Any ideas? Thanks in advance!
In order to make this work, you have to add an extra header to your request:
Accept: application/json
That did the trick.
You can use controller based validation as described in documentation https://laravel.com/docs/5.2/validation#manually-creating-validators
public function store(Request $request) {
$validator = Validator::make($request->all(), [
'question' => 'required|min:10|max:140',
'active' => 'boolean',
]);
if ($validator->fails()) {
return response()->json($validator->errors());
}
//other
}
I want to clear session variable only when I enter my symfony form first time. In this example session is delete even when form is not valid - how can I change this?
public function dodajNewAction(Request $request, Pacjent $pacjent)
{
unset($_SESSION['test']);
$wykbad = new Wykbadpoz($pacjent);
$wykbad->setRok(date('Y'));
$wykbad->setMiesiac(date('n')); //miesiac bez zera wiodacego
$form = $this->createForm('nfz_wykbadpoz_new', $wykbad);
$form->handleRequest($request);
return [
'form' => $form->createView()
];
}
In a Symfony project you should never use superglobals like $_SESSION ($_GET, $_POST, ...). You must use the Request object.
Like this:
public function dodajNewAction(Request $request, Pacjent $pacjent)
{
$wykbad = new Wykbadpoz($pacjent);
$wykbad->setRok(date('Y'));
$wykbad->setMiesiac(date('n')); //miesiac bez zera wiodacego
$form = $this->createForm('nfz_wykbadpoz_new', $wykbad);
$form->handleRequest($request);
$session = $request->getSession();
if ($form->isValid() && $session->has('test')) {
$session->remove('test');
}
return [
'form' => $form->createView()
];
}