2011-10-16 11 views
14

Estoy creando una aplicación web que involucra formularios. El marco utilizado es symfony2. Me gustaría tener todo funcionando para los usuarios sin javascript, y luego mejorar progresivamente la experiencia para las personas con javascript habilitado. Estoy planeando usar JQuery como mi biblioteca de JavaScript.Envío de formulario Ajax en symfony2 con degradación gradual para usuarios sin javascript

Me gustaría tener formularios donde enviar y muestra un mensaje utilizando el componente FlashMessage si el usuario no tiene javascript y la solicitud no es una solicitud AJAX.

Para usuarios con soporte de Javascript, me gustaría devolverles el mensaje si el envío se realiza correctamente. El javascript debería mostrar ese mensaje en un div inmediatamente.

Al mismo tiempo, necesito ocuparme de los mensajes de error. Para usuarios sin javascript, todo el formulario será reintegrado con los mensajes de error en su lugar.

Para los usuarios con javascript, la respuesta ajax debe ser una matriz que contenga la identificación del componente de entrada y el mensaje de error. Javascript debería insertarlos en el formulario sin una actualización.

Mirando el libro de Symfony2, puedo ver lo siguiente para presentaciones, que luego lo modificó para comprobar si la petición es una petición AJAX:

public function newAction(Request $request) 
{ 
    // just setup a fresh $task object (remove the dummy data) 
    $task = new Task(); 

    $form = $this->createFormBuilder($task) 
     ->add('task', 'text') 
     ->add('dueDate', 'date') 
     ->getForm(); 

    if ($request->getMethod() == 'POST') { 
     $form->bindRequest($request); 

     if ($form->isValid()) { 
      // perform some action, such as saving the task to the database 
      if ($this->request->isXmlHttpRequest(){ 
        //return data ajax requires. 
      } 
      return $this->redirect($this->generateUrl('task_success')); 
     } 
    } 

    // ... 
} 

El problema que encontramos con este enfoque es que es ISN muy elegante Necesito agregar ese cheque adicional en cada formulario. Además, este método no funcionaría si, por ejemplo, la solicitud entra por Zend_AMF.

¿Hay alguna forma mejor de hacerlo?

Respuesta

24

Otra opción es que su controlador devuelva algo más que una respuesta y utilice el evento kernel.view para transformarlo en lo que desee. Esto sería mejor DRY porque la lógica está encapsulada en el oyente. Solo necesita decidir qué desea que devuelvan sus controladores.

if ($form->isValid()) { 
    return new Something($redirectUrl, $ajaxData); 
} 

Y en su oyente:

public function onKernelView($event) 
{ 
    $request = $event->getRequest(); 
    $result = $event->getControllerResult(); 

    if ($result instanceof Something) { 
     if ($request->isXmlHttpRequest()) { 
      $event->setResponse(new Response(json_encode($result->getAjaxData()))); 
     } else { 
      $event->setResponse(new RedirectResponse($result->getRedirectUrl())); 
     } 
    } 
} 
2

Mientras se puede generalizar el tipo de respuesta necesaria para las formas no Ajax y de formas ajax, puede relegar a que la decisión de ajax/no-ajax a otro método y luego simplemente tener:

return handleResponseType(whateverInfoIsNeededToHandleIt) 

Usted tiene control total sobre lo que se transfiere a su función de decisión.

5

Puede devolver una respuesta como de costumbre y decidir sobre la vista si usted quiere hacer un render parcial o hacer toda la página mediante la ampliación de diferentes diseños ramita.

En su controlador:

if ($form->isValid()) { 
    // perform some action, such as saving the task to the database 
    $this->get('session')->setFlash('notice', 'Success!'); 
    return $this->render('success.html.twig'); 
} else { 
    $this->get('session')->setFlash('notice', 'Please correct the errors below'); 
} 

Y en sus puntos de vista:

{# new.html.twig #} 
{% extends app.request.isXmlHttpRequest ? 'ajax.html.twig' : 'layout.html.twig' %} 
{% block content %} 
    {% if app.session.hasFlash('notice') %} 
     <div class="flash-notice">{{ app.session.flash('notice') }}</div> 
    {% endif %} 
    <form ...> 
     {{ form_widget('form') }} 
     <input type="submit" /> 
    </form> 
{% endblock %} 


{# success.html.twig #} 
{% extends app.request.isXmlHttpRequest ? 'ajax.html.twig' : 'layout.html.twig' %} 
{% block content %} 
    {% if app.session.hasFlash('notice') %} 
     <div class="flash-notice">{{ app.session.flash('notice') }}</div> 
    {% endif %} 
{% endblock %} 


{# ajax.html.twig #} 
{% block content %}{% endblock %} 


{# layout.html.twig #} 
<html> 
<body> normal page content 
    <div id='content'> 
    {% block content %}{% endblock %} 
    </div> 
</body> 
</html> 

(Es posible que desee poner la parte mensajes flash en una macro o un include ...)

Ahora simplemente rinden el retorno de la petición Ajax en la etiqueta que desea colocarlo:

$.ajax({ 
    type: "POST", 
    url: "tasks/new", 
    data: {task: foo, dueDate: bar}, 
}).done(function(msg) { 
    $('#content').html(msg); 
}); 
Cuestiones relacionadas