Lajos Arpad
Lajos Arpad

Reputation: 76717

Is there a way to send a GET request using forms in Symfony and avoid reloading the page while changing the URL?

I have the following form type:

<?php

namespace Myproject\App\ErpBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\FormEvent;
use Myproject\OrderBundle\Entity\OrderProductType;
use Myproject\OrderBundle\Entity\OrderOrder;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\HttpFoundation\RequestStack;

class OrderSearchType extends AbstractType
{
    protected $em;
    protected $container;
    protected $requestStack;

    public function __construct(ObjectManager $em, ContainerInterface $container, RequestStack $requestStack)
    {
        $this->em = $em;
        $this->container = $container;
        $this->requestStack = $requestStack;
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $data = $builder->getData();
        $currentRequest = $this->requestStack->getCurrentRequest();
        $pt = [
            'class' => OrderProductType::class,
            'choices' => [],
            'required' => false
        ];
        if ($productType = $currentRequest->query->get('ProductType', null)) {
            $pt["data"] = $productType;
        }
        $id = [
            'label' => 'id',
            'required' => false
        ];
        if ($idValue = $currentRequest->query->get('id', null)) {
            $id["data"] = $idValue;
        }
        $name = [
            'label' => 'név',
            'required' => false
        ];
        if ($nm = $currentRequest->query->get('name', null)) {
            $name["data"] = $nm;
        }
        $builder
            ->add('productType', EntityType::class, $pt)
            ->add('id', IntegerType::class, $id)
            ->add('name', TextType::class, $name)
            ->add('status', ChoiceType::class, [
                'choices' => [  'Bármilyen',
                                OrderOrder::$ORDER_STATUS_TEXT[OrderOrder::$ORDER_STATUS_ORDERED],
                                OrderOrder::$ORDER_STATUS_TEXT[OrderOrder::$ORDER_STATUS_ACCEPTED],
                                OrderOrder::$ORDER_STATUS_TEXT[OrderOrder::$ORDER_STATUS_REFUSED]
                            ],
                'data' => $currentRequest->query->get('status', "1")
            ])
            ->add('search', SubmitType::class, [
                'label' => 'Keresés',
                'attr' => ['class' => 'btn btn-primary btn-sm']
            ]);

        $builder->addEventListener(FormEvents::PRE_SUBMIT, array($this, 'onPresubmit'));
        $builder->addEventListener(FormEvents::POST_SET_DATA, array($this, 'onPostSetData'));
    }

    public function onPostSetData(FormEvent $event)
    {
        $form = $event->getForm();
        $data = $form->getData();
        $event->getForm()
            ->add('productType', EntityType::class, [
                'class' => OrderProductType::class,
                'choices' => $this->em->getRepository(OrderProductType::class)->findAll(),
                'choice_label' => function($orderProductType = null) {
                    return sprintf($orderProductType ? $orderProductType->getTitle() : "Kérem válasszon");
                },
                'label' => 'Termékfajta',
                'required' => false,
                'attr' => [
                    'class' => 'selectpicker',
                    'data-live-search' => 'true'
                ]
            ]);
    }

    public function onPresubmit(FormEvent $event)
    {
        $form = $event->getForm();
        $data = $event->getData();
        $event->getForm()
            ->add('productType', EntityType::class, [
                'class' => OrderProductType::class,
                'choices' => $this->em->getRepository(OrderProductType::class)->findAll(),
                'choice_label' => function($orderProductType = null) {
                    return sprintf($orderProductType ? $orderProductType->getTitle() : "Kérem válasszon");
                },
                'label' => 'Termékfajta',
                'required' => false,
                'attr' => [
                    'class' => 'selectpicker',
                    'data-live-search' => 'true'
                ]
            ]);
    }
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => null,
            'em' => $this->em,
        ]);

        parent::configureOptions($resolver);
    }

    public function getBlockPrefix()
    {
        return 'route';
    }
}

It is displayed on the ui like this:

            {{ form_start(form, { 'attr': {'class': 'myprojectAdminForm pull-right', 'id': form.vars.name } }) }}
                Szűrés: 
                {{ form_widget(form.productType) }}
                {{ form_widget(form.id, {'attr': {'placeholder': form.id.vars.label, 'class':'form-control'}}) }}
                {{ form_widget(form.name, {'attr': {'placeholder': form.name.vars.label, 'class':'form-control' }}) }}
                {{ form_widget(form.status, {'attr': {'class':'form-control'}}) }}
                {{ form_widget(form.search) }}
                {{ form_widget(form._token) }}
                {{ form_errors(form) }}
            {{ form_end(form, {'render_rest': false}) }}

and whenever the user clicks on search, the following Javascript is executed:

    $("#erpordersearch_search").click(function(e) {
        e.preventDefault();
        var productTypeID = document.querySelector("#erpordersearch_productType").value;
        var ID = document.getElementById("erpordersearch_id").value;
        var name = document.getElementById("erpordersearch_name").value;
        var status = document.getElementById("erpordersearch_status").value;
        var url = window.location.href.substring(0, window.location.href.lastIndexOf("/page"));
        url = url + "/page1";
        window.location.href = url + "[ProductTypeID=" + productTypeID + "&id=" + ID + "&name=" + name + "&status=" + status + "]";
    });

This works, but the problem is that I am tracking user action history on the ui and if the system loads the full page, then I am losing all the history of the user's action, as the history is saved in the Javascript. I know I could save the history in the database or localStorage, but either of those are not viable options in my case, as they would violate the policies of the project. I was asked to do modifications which will consist of the following features:

I have been given some vague description about how this should be achieved via the combination of Symfony and the particular project I am working on, but it is unclear and contains project-specific information I cannot share here.

So my question is: is there a way using PHP and Symfony, to change the URL when sending a request and still keeping all the variables which were defined in Javascript?

Upvotes: 0

Views: 376

Answers (1)

Hex
Hex

Reputation: 241

The only way I would say this is possible (prepare for more vague explanations) is to have your JavaScript variables stored in invisible form elements that are submitted on pressing the search button.

These should then be sent to the Symfony controller via post data, form here you can then use the method outlined here to send variables to JavaScript from PHP (but modified for twig syntax) - How can I store JavaScript variable output into a PHP variable?

If in a script file, you can try passing arguments this way - https://www.gun.io/blog/pass-arguments-to-embedded-javascript-tutorial-example


EDIT

After reading over this all again (and discussing this in the comments below), I think I understand the question better.

I personally agree with you, it looks like this will be impossible to do in pure Symfony via GET requests.

Even if there was a "hacky" method, it wouldn't be scaleable or dynamic and thus not worth doing.

Upvotes: 1

Related Questions