Este foro ya no está activo, así que no puedes publicar nuevas preguntas ni responder a las preguntas existentes.

Ajax con Symfony2

16 de junio de 2015

¿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

#1

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

17 junio 2015, 8:46
#2

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

17 junio 2015, 15:40
#3

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

17 junio 2015, 15:50
#4

@javiereguiluz gracias por responder, ya voy a revisar bien eso.

@piocarluis

17 junio 2015, 16:30
#5

@javiereguiluz aun no puedo implementar lo de ajax, podrias ayudarme con un ejemplo sencillo pero completo, te lo agradecería mucho.

@piocarluis

18 junio 2015, 16:22
#6

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

18 junio 2015, 16:48
#7

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

18 junio 2015, 17:21
#8

@piocarluis gracias por compartir con nosotros la solución completa.

@javiereguiluz

18 junio 2015, 17:56
#9

@javiereguiluz no hay de que, lo importante es ayudar a los que necesitan.

@piocarluis

18 junio 2015, 21:11
#10

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

19 noviembre 2015, 12:20
#11

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

19 noviembre 2015, 20:43