¿Alguien tiene idea o una página que expliquen bien como trabajar Symfony2 con Ajax? porque tengo una página Twig con menú pero quiero que todo lo que se selecciona en el menú, aparezca en el <div>
principal que tengo en medio de mi pantalla sin direccionar al usuario a otra pantalla.
Gracias de antemano.
Respuestas
No hay ninguna diferencia entre trabajar con o sin Ajax en una aplicación Symfony. Lo único que tendrás que tener en cuenta es que si quieres devolver respuestas JSON por ejemplo, en tu controlador deberías usar JsonResponse()
en vez del Response()
normal.
De la misma forma, si quieres hacer que un controlador solo funcione con Ajax, puedes usar el método isXmlHttpRequest()
:
public funcion indexAction(Request $request) { if (!$request->isXmlHttpRequest()) { // error ... } // ... }
Por último, otro truco habitual es hacer que el layout
que decora las plantillas solo se aplique si la petición no es Ajax. Puedes hacerlo de esta manera:
{# app/Resources/views/layout.html.twig #} {% extends app.request.xmlHttpRequest ? 'layout_ajax.html.twig' : 'layout_completo.html.twig' %}
@javiereguiluz
Que tal @javiereguiluz, gracias por responder, pero no lo tengo tan claro. La parte que no entiendo es que cómo hago que cuando el usuario de clic en una pestaña del menú, muestre una plantilla en mi <div>
principal que tengo en mi hoja twig y cuando seleccione otra opción mandarle otra plantilla twig en la misma página pero ya en el <div>
principal le tiene que salir la otra opción que seleccionó.
@piocarluis
La parte que se encarga de hacer peticiones Ajax al servidor, recibir los contenidos, procesarlos y reemplazar los <div>
de la página lo tienes que hacer con JavaScript. Por lo tanto, en esa parte Symfony no se mete y puedes usar lo que quieras: desde un simple pero efectivo código jQuery hasta una aplicación AngularJS.
Lo que se me ha olvidado comentarte antes es que deberías usar también el bundle FOSJsRoutingBundle. Con este bundle puedes generar rutas en JavaScript de la misma manera que las generas en las plantillas Twig. Esto es imprescindible para que puedas hacer correctamente las peticiones Ajax al servidor.
@javiereguiluz
@javiereguiluz gracias por responder, ya voy a revisar bien eso.
@piocarluis
@javiereguiluz aun no puedo implementar lo de ajax, podrias ayudarme con un ejemplo sencillo pero completo, te lo agradecería mucho.
@piocarluis
No conozco ejemplos completos de aplicaciones open source que usen Symfony con Ajax, pero en Internet hay muchos artículos que explican cosas concretas sobre este tema. Por ejemplo:
En cualquier caso, te vuelvo a decir que desde el punto de vista de Symfony, que la aplicación use Ajax o no es irrelevante. Si la aplicación usa Ajax, el código del servidor es casi el mismo (sólo tendrás que incluir pequeños cambios como que en vez de Response
usas JsonResponse
, etc.) El verdadero trabajo está en la parte del navegador, ya que el código JavaScript se te va a complicar bastante. Pero ahí Symfony no puede intervenir de ninguna manera.
@javiereguiluz
Pude hacerlo, lo hice sin tocar el controlador solo haciendo la logica en la plantilla, lo voy a compartir con ustedes por si acaso algo lo necesite:
En la pagina home de twig o en la pagina index o principal que tu tengas ponemos el siguiente codigo, solo hay que adaptarlo a lo que necesites voy a dejar comentado que se tendria que adaptar o cambiar
<script type="text/javascript"> function ajaxget(){ var conexion; if(window.XMLHttpRequest) { conexion=new XMLHttpRequest(); } else { conexion=new ActiveXObject("Microsoft.XMLHTTP"); } conexion.onreadystatechange = function() { if(conexion.readyState==4 && conexion.status==200) { /* esta parte donde dice principal, ese es el nombre del div que tenemos en la pagina home que es donde se va a mostrar la información cuando el usuario de clic en un enlace */ document.getElementById("principal").innerHTML=conexion.responseText; } } /* en el segundo parametro puede ir una direccion a la cual se va a dirigir ya sea web/otra_pagina o mas fácil seria poner el nombre de la ruta que tenemos en el routing usando la funcion path como esta en el ejemplo */ conexion.open("GET",{{path('nombre_del_routing')}},true); conexion.send(); } </script>
Este es el enlace que cuando el usuario da clic se ejecuta la funcion ajaxget()
que es la que está arriba:
<a href="#" onclick="ajaxget()">Enlace</a>
No olvidar que en la misma página home hay que tener un <div>
con su id
. En este caso yo tengo:
<div id="principal"> </div>
Recuerde que en ese <div>
se va a presentar la plantilla que le hemos asignado en conexion.open
en nuestro script.
Informacion adicional: así tengo mi ruta:
nombre_del_routing: path: /otra_pagina defaults: { _controller: Bundle:Default:otraPagina }
Wsto es un ejemplo de cómo tengo mi routing donde dice nombre_del_routing
ese nombre le van a poner al segundo parámetro que les dije arriba en conexion.open
dentro de las etiquetas JavaScript.
Recuerden borrar los comentarios cuando copien el código, ya que después da error.
Espero que a alguien les sirva si caen en esta página. Suerte.
@piocarluis
@piocarluis gracias por compartir con nosotros la solución completa.
@javiereguiluz
@javiereguiluz no hay de que, lo importante es ayudar a los que necesitan.
@piocarluis
Buenas tardes, Antes de nada agradeceros vuestra ayuda y colaboración.
Estoy intentando implementar en mi pagina una opción de favoritos para unas fotos de una galería.
Para ellos y recordar los favoritos de todos los usuarios, los almacenos una base de datos, hasta aqui todo correcto.
Hago la llamada ajax
$.ajax({ url: Routing.generate('favoritos', { foto: 15, usuario: 15 }), dataType : 'html', type : 'POST', success: function(respuesta){ alert('correcto'); }, error : function(xhr, status) { alert('ERROR -> '. status); } });
Llego hasta el controlador
public function favoritosAction($foto, $usuario) { if ($this->getDoctrine()->getRepository('AppBundle:usuarios_fotos')->findBy(array('foto' => $foto, 'usuario'=> $usuario))) { $respuesta = 'Ya en favoritos'; } else { $Usuarios_Fotos = new usuarios_fotos; $Usuarios_Fotos->setFoto($this->getDoctrine()->getRepository('AppBundle:fotos')->find($foto)); $Usuarios_Fotos->setUsuario($this->getDoctrine()->getRepository('AppBundle:Usuarios')->find($usuario)); $em = $this->getDoctrine()->getEntityManager(); $em->persist($Usuarios_Fotos); $em->flush(); $respuesta = 'Correcto'; } // replace this example code with whatever you need return $this->render('default/favorito.html.twig', array( 'respuesta' => $respuesta, 'base_dir' => realpath($this->container->getParameter('kernel.root_dir').'/..'), )); }
El problema o duda que tengo es que solo necesitaría devolver si todo ha ido bien, o mal.
Igual estoy matando moscas a cañonazos, el código de arriba me funciona, pero no consigo comunicar la respuesta ajax con mi plantilla de la galería.
Gracias por vuestra ayuda.
@es_11400
Buenas de nuevo,
He conseguido resolverlo, sustituyendo el render por un response
// replace this example code with whatever you need return $this->render('default/favorito.html.twig', array( 'respuesta' => $respuesta, 'base_dir' => realpath($this->container->getParameter('kernel.root_dir').'/..'),
Por ->
return new Response($respuesta);
Gracias, aunque si estoy haciendo una barbaridad y hay otra forma mejor, serán bien recibidos vuestros consejos.
@es_11400