Refresh page in symfony2 at the end of Ajax call - ajax

How can I refresh a page after an ajax call is executed.
My Ajax call is
$.ajax({
type: "POST",
data: data,
url:"{{ path('v2_pm_patents_trashpatents') }}",
cache: false
});
The method that is executed by this ajax is
public function trashpatentAction(Request $request){
if ($request->isXmlHttpRequest()) {
$patent_id = $request->get("pid");
$em = $this->getDoctrine()->getEntityManager();
$patent = $em->getRepository('MunichInnovationGroupPatentBundle:SvPatents')->find($patent_id);
if (!$patent) {
throw $this->createNotFoundException('No patent found for id '.$patent_id);
}
$patent->setIs_deleted(1);
$em->flush();
}
}
Edit
Portfolio Controller Index Action
public function indexAction(Request $request) {
$switch_form = $this->createForm(new SwitchPortfolioType($portfolios));
////rest of action code
return $this->render('MunichInnovationGroupPatentBundle:Portfolio:index.html.twig', array('new_patentgroup_form' => $new_patentgroup_form->createView(),'switch_form' => $switch_form->createView(), 'new_form' => $new_form->createView(), "portfolios" => $portfolios ,"selected_portfolio" => $selected_portfolio,"portfolio_groups" => $portfolio_groups,"patents" => $patents));
}
Index.html.twig
<form name="portfolios" action="{{ path('v2_pm_portfolio') }}" method="post" >
{{ form_widget(switch_form) }}
<input type="submit"class="portfolio_input button2 tooltip" value="Switch">
</form>
SwitchPortfolioType
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
class SwitchPortfolioType extends AbstractType
{
public function __construct($portfolios)
{
$this->portfolios = $portfolios;
}
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('', 'choice', array(
'choices' => array(
'test' => 'Test'
),
'empty_value' => 'Switch your Portfolio',
));
}
public function getName()
{
return 'switch_portfolio';
}
}
At the end of this action I want to refresh the page
How can I do this?

The refresh will have to be done in javascript. I am not sure why you would POST via ajax only to reload the page anyway, why not just POST normally?
Anyway, to do what you ask I would return some simple JSON response in the controller to signify a success and then in the ajax callback do this:
$.ajax({
type: "POST",
data: data,
url:"{{ path('v2_pm_patents_trashpatents') }}",
cache: false,
success: function(data) {
// optionally check if the response is what you wanted
//if (data.response == 'deleted') {
document.location.reload(true);
//}
}
});

Using jQUery:
$('your_form').disable=true;
Pure JS:
your_form.disabled = true;

Related

Symfony 5 / Request Response : Get data with Ajax

when I try to get data in ajax, the returned object is empty
I send the id of the data I want to get in js :
function selectMessage(id) {
$.ajax({
url: '{{ path('back_translation_update') }}',
method: 'GET',
data: {id: id}
}).done(function (response) {
console.log(response)
})
}
$('.updateMessage').click(function (evt) {
evt.stopPropagation()
selectMessage($(this).data('id'))
})
in the controller I look for the data to return :
/**
* #Route("/update", name="back_translation_update", methods="GET|POST")
*/
public function getById(Request $request): Response
{
if ($request->isXMLHttpRequest()) {
$id = $request->get('id');
// dd($id);
$message = $this->translationService->getTranslationById($id);
// return new JsonResponse(['data' => $message]);
$response = new Response();
$response->setContent(json_encode([
'data' => $message,
]));
$response->headers->set('Content-Type', 'application/json');
return $response;
}
}
I use a service because with the repository I get an error: getById () must be an instance of Symfony\Component\HttpFoundation\Response
with :
$repositoryMessage = $this->em->getRepository(TranslationMessage::class);
$message = $repositoryMessage->findOneBy(['id' => $id]);
so the service will look in the database:
public function getTranslationById($translation_id)
{
$query = $this->em->createQueryBuilder()
->from(TranslationMessage::class,'message')
->select('message')
->where('message.id = ?1')
->setParameter(1, $translation_id);
$message = $query->getQuery()->getResult();
// dd($message);
return $message;
}
all the dd() give the expected values:
into getById(): the id of the row sought
into getTranslationById(): the sought object
but in the XHR, data contains an empty object: uh:
same with a new JsonResponse, commented here
what did I miss? help
Use Aurowire to get messageRepository object and use $this->json() to return JsonResponse
/**
* #Route("/update", name="back_translation_update", methods="GET|POST")
*/
public function getById(Request $request, TranslationMessageRepository $messageRepository): JsonResponse
{
$id = $request->query->get('id');
$message = $messageRepository->find($id);
if(!$message) { return new NotFoundHttpException(); }
return $this->json([
'success' => true,
'data' => $message
]);
}
Define success function instead of done function
function selectMessage(id) {
$.ajax({
url: "{{ path('back_translation_update') }}",
method: 'GET',
data: { id: id }
success: function(data) {
console.log(data)
}
})
}

The Ajax pagination to my account not run

I would like to create an Ajax pagination of my articles in my account, here is my code that I created but it does not work I do not know how to do.
MyaccountController
public function viewProfile($username) {
if($username) {
$user = User::where('username', $username)->firstOrFail();
} else {
$user = User::find(Auth::user()->id);
}
return view('site.user.account', [
'user' => $user,
'articles' => $user->articles()->orderByDesc('created_at')->paginate(4),
]);
}
I would like to have the javascript code
$(document).ready(function () {
$(document).on('click','.pagination a',function(e){
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
var url = $(this).attr('href');
$.ajax({
url: url,
method: 'GET',
data: {},
dataType: 'json',
success: function (result) {
if (result.status == 'ok'){
$('#userListingGrid').html(result.listing);
}else{
alert("Error when get pagination");
}
}
});
return false;
})
});
I would have a check on your controller for an ajax request like so:
public function viewProfile($username) {
if($username) {
$user = User::where('username', $username)->firstOrFail();
} else {
$user = User::find(Auth::user()->id);
}
if(request()->ajax()){
return response()->json(['user' => $user, 'articles' => $user->articles()->orderByDesc('created_at')->paginate(4);
}
return view('site.user.account', [
'user' => $user,
'articles' => $user->articles()->orderByDesc('created_at')->paginate(4),
]);
}
Then you don't have to load your view every time and you can let your javascript functions take care of the DOM manipulating of the results. Not sure if that's what you are looking for. I know that you would probably need a {{$articles->links()}} at the end of your view to go through each page.

Symfony2: Save Record From Ajax Form Submission

I am totally lost. There's only so much documentation one can read before it all starts making zero sense.
I want to be able to save form data passed from outside of my Symfony application. I have already installed FOSRestBundle, JMSSerializerBundle, NelmioCorsBundle, etc.
First off, I have a FormType that looks like this:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title')
->add('requestDate')
->add('deliverDate')
->add('returnDate')
->add('created')
->add('updated')
->add('contentChangedBy')
;
}
Then I have a REST controller containing the POST method which is supposed to store the new record:
class AvRequestController extends Controller
{
...
public function postAvrequestAction(Request $request){
$entity = new AvRequest();
$form = $this->createForm(new AvRequestType(), $entity);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
return new \Symfony\Component\HttpFoundation\JsonResponse($entity, Codes::HTTP_CREATED);
}
return new \Symfony\Component\HttpFoundation\JsonResponse($request, 400);
}
}
Here is the test with the mock ajax form data:
$('#postform').submit(function(event){
event.preventDefault();
console.log("submitted");
ajaxObject = {
url: $("#postform").attr("action"),
type: 'POST', // Can be GET, PUT, POST or DELETE only
dataType: 'json',
xhrFields: {
withCredentials: true
},
crossDomain: true,
contentType: "application/json; charset=UTF-8",
data: JSON.stringify({"id":2, "title":"billabong", "requestDate":"2000-01-01 11:11:11", "deliverDate": "2000-01-01 11:11:11", "returnDate": "2000-01-01 11:11:11", "created": "2000-01-01 11:11:11", "updated": "2000-01-01 11:11:11", "content_changed_by":"cpuzzuol"})
};
// ... Add callbacks depending on requests
$.ajax(ajaxObject)
.done(function(data,status,xhr) {
console.log( two );
})
.fail(function(data,status,xhr) {
console.log( status );
})
.always(function(data,status,xhr) {
console.log( data );
});
console.log("END");
});
When I submit the form, the 400 Bad Request is tripped in my POST method. Worse, my $request bag is always empty:
{"attributes":{},"request":{},"query":{},"server":{},"files":{},"cookies":{},"headers":{}}
If I do
$request->getContent()
I get my stringified data:
"{\u0022id\u0022:2,\u0022title\u0022:\u0022billabong\u0022,\u0022requestDate\u0022:\u00222000-01-01 11:11:11\u0022,\u0022deliverDate\u0022:\u00222000-01-01 11:11:11\u0022,\u0022returnDate\u0022:\u00222000-01-01 11:11:11\u0022,\u0022created\u0022:\u00222000-01-01 11:11:11\u0022,\u0022updated\u0022:\u00222000-01-01 11:11:11\u0022,\u0022content_changed_by\u0022:\u0022cpuzzuol\u0022}"
I've read that this might have something to do with FOSRestBundle's "body listener" but I've already enabled that:
body_listener: true
UPDATE
body_listener doesn't seem to play a role at all. As the answer below states, you have to create a form with a blank name since the form you are submitting from outside of the system isn't going to have the name it would normally have if it were made inside of Symfony. Also, make sure to turn off CSRF if you don't have that set up at first.
Form isValid checks also for CSRF token validation. You can turn off csrf token validation in AvRequestType.
//...
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\AvRequest',
'csrf_protection' => false
));
}
//...
Also, I suggest your form has name. isValid also checks for your form name.
// form without name
public function getName()
{
return '';
}
Or
$form = $this->get('form.factory')->createNamed('', new AvRequestType(), $avRequest);
If you want to create entity, you should send data without id(from JS).
I have used "JMS serializer" to serialize my entity to json.
//Controller
public function postAvRequestAction(Request $request)
{
$avRequest = new AvRequest();
$form = $this->createForm(new AvRequestType(), $avRequest);
$form->handleRequest($request);
$form = $this->get('form.factory')->createNamed('', new AvRequestType(), $avRequest);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($avRequest);
$em->flush();
$serializer = $this->get('serializer');
$serialized = $serializer->serialize($avRequest, 'json');
return new Response($serialized);
}
return new JsonResponse(array(
'errors' => $this->getFormErrors($form)
));
}
protected function getFormErrors(Form $form)
{
$errors = array();
foreach ($form->getErrors() as $error) {
$errors['global'][] = $error->getMessage();
}
foreach ($form as $field) {
if (!$field->isValid()) {
foreach ($field->getErrors() as $error) {
$errors['fields'][$field->getName()] = $error->getMessage();
}
}
}
return $errors;
}

How to update pagination template of knppaginatorbundle after ajax query

Im using knppaginatorbundle to create pagination. I have created a jquery code to select data with ajax.
Everything is okay when I click on the page number , the content is loaded with the correct data.
But I have a problem , The pagination template is not changed after after ajax query:
previous and next links values must changed
current page must be disabled
and other changes that need to be done ...
How can I do this ?
public function listAction($page, Request $request)
{
$em = $this->getDoctrine()->getManager();
$paginator = $this->get('knp_paginator');
$qb = $em->getRepository('AppBundle:Travel')->getListTravels();
$pagination = $paginator->paginate(
$qb, $request->query->get('page', $page), 3
);
//ajax request
if ($request->isXmlHttpRequest()) {
$view = $this->renderView('#App/Frontend/Travel/list.html.twig', array(
'pagination' => $pagination
));
$response = new JsonResponse(array('ok' => $view));
return $response;
}
return $this->render('AppBundle:Frontend/Travel:travel-list-view.html.twig', array(
'pagination' => $pagination,
));
}
I have added an attr data-target to pagination template like this:
<a data-target="{{ page }}" href="{{ path(route, query|merge({(pageParameterName): page})) }}">{{ page }}</a>
View
//.....
<div id="mydiv">
// list.html.twig contains the loop
{% include "AppBundle:Frontend/Travel:list.html.twig" %}
</div>
<br>
{{ knp_pagination_render(pagination) }}
//....
<script>
$(document).ready(function () {
$("ul#pagination a").click(function (e) {
e.preventDefault();
var dataTarget = $(this).attr("data-target"); // each <a> has attr named data-target contains num of page
var hash;
hash = 'page=' + dataTarget;
window.location.hash = hash;
if (window.location.hash != "") {
$.ajax({
type: 'get',
dataType: 'json',
url: Routing.generate('frontend_travels_list', {'page': dataTarget}),
success: function (msg) {
if (msg["ok"] === undefined) {
alert('error');
} else {
$("#mydiv").html(msg["ok"]);
}
}
});
}
});
});
</script>
Route
frontend_travels_list:
path: /travels/{page}
defaults: { _controller: AppBundle:TravelFrontend:list, page: 1 }
options:
expose: true
If someone else needs a solution there 2 ways.
You can use that bundle https://github.com/nacholibre/knppaginator-ajax
You should build new pagination string in controller and send it in JsonResponse as a param. Then replace pagination element in DOM via jQuery on success.
For SF 4.3 you can use my approach
To be able to inject the Processor in controller you have to add alias for autowiring in services.yaml
Knp\Bundle\PaginatorBundle\Helper\Processor: '#knp_paginator.helper.processor'
Based on injected PaginatorInterface you should build your $pagination object (PaginationInterface)
Use Processor to build the context array for Twig.
$paginationContext = $processor->render($pagination);
render method expects SlidingPagination object, but got $pagination which is PaginationInterface - however it seems that is ok
Get the Twig and render a final string
$twig = $this->get('twig');
$paginationString = $twig->render($pagination->getTemplate(), $paginationContext);
Example of working controller
if ($request->isXmlHttpRequest()) {
$view = $this->render('#App/Frontend/Travel/list.html.twig', array(
'pagination' => $pagination
))->getContent();
$paginationContext = $processor->render($pagination);
$twig = $this->get('twig');
$paginationHtml = $twig->render($pagination->getTemplate(), $paginationContext);
$response = new JsonResponse(['view' => $view, 'paginationHtml' => $paginationHtml]);
return $response;
}
then in jQuery
success: function (msg) {
if (msg["ok"] === undefined) {
alert('error');
} else {
$("#mydiv").html(msg["view"]);
$("#myDivContainingPagination").html(msg["paginationHtml"])
}
}

Ajax query works when adding new post but doesn't work when update an entity

I have two Select box one for the Countries and the second for the cities and the second one depends from the selected choice of the first one.
I the code is as the example Dynamic Generation for Submitted Forms in the documentation http://symfony.com/doc/current/cookbook/form/dynamic_form_modification.html#cookbook-form-events-submitted-data
All things work fine when adding a new post , but when trying do update a post, the Ajax query to display cities doesn't work .
This is the controller
// newAction
/**
* #ParamConverter("agence", options={"mapping": {"agence_slug":"slug"}})
*/
public function newAction(Agence $agence, Request $request)
{
$em = $this->getDoctrine()->getManager();
$travel = new Travel();
$form = $this->createForm(new TravelType($agence), $travel);
if ($request->getMethod() == 'POST')
{
//....
}
return $this->render('AppBundle:Dashboard/Travel:new.html.twig',
array(
'form' => $form->createView() ,
'agence' => $agence,
));
}
//editAction
/**
* #ParamConverter("agence", options={"mapping": {"agence_slug":"slug"}})
* #ParamConverter("travel", options={"mapping": {"travel_id":"id"}})
*/
public function editAction(Travel $travel, Agence $agence, Request $request)
{
$em = $this->getDoctrine()->getManager();
$form = $this->createForm(new TravelEditType($agence), $travel);
if ($request->getMethod() == 'POST'){
//....
}
return $this->render('AppBundle:Dashboard/Travel:edit.html.twig',
array(
'form' => $form->createView() ,
'travel' => $travel,
'agence' => $agence,
));
}
travelType and ti works good
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormEvent;
//........
use Symfony\Component\Form\FormInterface;
use AppBundle\Entity\Country;
class TravelType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
//....
$formModifier = function (FormInterface $form, Country $country = null) {
$cities = null === $country ? array() : $country->getCities();
$form->add('destination', 'entity', array(
'class' => 'AppBundle:CityWorld',
'choices' => $cities,
'multiple' => false,
'expanded' => false,
'property' => 'name',
'label' => 'Destination',
'attr' => array('class' => 'col-xs-10 col-sm-10', 'placeholder' => 'Destination'),
));
};
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (FormEvent $event) use ($formModifier) {
// this would be your entity, i.e. SportMeetup
$data = $event->getData();
$formModifier($event->getForm(), $data->getCountry());
}
);
$builder->get('country')->addEventListener(
FormEvents::POST_SUBMIT,
function (FormEvent $event) use ($formModifier) {
// It's important here to fetch $event->getForm()->getData(), as
// $event->getData() will get you the client data (that is, the ID)
$country = $event->getForm()->getData();
// since we've added the listener to the child, we'll have to pass on
// the parent to the callback functions!
$formModifier($event->getForm()->getParent(), $country);
}
);
$builder->addEventListener(FormEvents::POST_SUBMIT, function ($event) {
$event->stopPropagation();
}, 90000000000000); // Always set a higher priority than ValidationListener
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Travel'
));
}
public function getName()
{
return null;
}
}
This is TravelEditType
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormEvent;
//........
use Symfony\Component\Form\FormInterface;
use AppBundle\Entity\Country;
class TravelEditType extends TravelType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
parent::buildForm($builder, $options) ;
}
public function getName()
{
return null;
}
}
This is the form and javascript code
<form method="post" action="" class="form-horizontal" role="form" {{ form_enctype(form) }} >
//.............
</form>
<script type="text/javascript">
var $county = $('#country');
$county.change(function () {
// ... retrieve the corresponding form.
var $form = $(this).closest('form');
var data = {};
data[$county.attr('name')] = $county.val();
// Submit data via AJAX to the form's action path.
$.ajax({
url: $form.attr('action'),
type: $form.attr('method'),
data: data,
success: function (html) {
// Replace current position field ...
$('#city').replaceWith(
// ... with the returned one from the AJAX response.
$(html).find('#city')
);
// Position field now displays the appropriate positions.
}
});
});
Try it without parameter in URI:
dashboard_city_ajax:
path: /citiies/ajax
defaults: { _controller: AppBundle:TravelDashboard:ajaxCities }
And send data with POST:
$.ajax({
url: '{{ path('dashboard_city_ajax') }}',
type: 'POST',
data: { agence_slug: '{{ agenceSlug }}' },
You can receive it in controller:
$request->request->get('bar', 'default value if bar does not exist');
The problem is in your route matching. There is many way to solve problem. Try just include in your ajax route requirements for matching route or in $.ajax function use another route, for example
The simplest way for you (if you don't want rebuild your controller) is just rebuild your route and put in the first place your ajax route like :
dashboard_city_ajax:
path: /{ajax}/{agence_slug}/citiies
defaults: { _controller: AppBundle:TravelDashboard:ajaxCities }
requirements:
ajax: ajax
$.ajax({
url: '{{ path('dashboard_city_ajax', {'agence_slug': agence.slug, 'ajax': 'ajax' }) }}',
type: 'POST',
data: data,
But the right way IMHO is get your data from request. For example
vplanning_ajax:
path: /ajax
defaults: { _controller: VplanningPageBundle:Page:Ajax }
function getData(init) {
$.post(
{{ path('vplanning_ajax') }},
{
agence_slug: agence.slug,
yourdata2: 'yourdata2
} ,
function ( data ) {
handleData(data);
}
);
}
And in your Controller your just do
$agence_slug = $this->request->request->get('agence_slug');
$yourdata2 = $this->request->request->get('yourdata2);
...

Resources