Отправка Ajax-формы в symfony2 с постепенной деградацией для пользователей без JavaScript - PullRequest
14 голосов
/ 16 октября 2011

Я создаю веб-приложение, которое включает в себя формы. Используемая платформа - это symfony2. Я хотел бы, чтобы все работало для пользователей без javascript, а затем постепенно улучшал работу с людьми с включенным javascript. Я планирую использовать JQuery в качестве библиотеки JavaScript.

Я хотел бы иметь формы, в которых он отправляет и отображает сообщение с использованием компонента FlashMessage, если у пользователя нет javascript и запрос не является ajax-запросом.

Для пользователей с поддержкой javascript, я хотел бы вернуть им сообщение, если отправка прошла успешно. Затем javascript должен немедленно отобразить это сообщение в div.

В то же время мне нужно иметь дело с сообщениями об ошибках. Для пользователей без JavaScript вся форма будет перерисована с сообщениями об ошибках на месте.

Для пользователей с javascript ответом ajax должен быть массив, содержащий идентификатор компонента ввода и сообщение об ошибке. Затем Javascript должен вставить их в форму без обновления.

Глядя на книгу по symfony2, я вижу следующее для представления, затем я изменил его, чтобы проверить, является ли запрос 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'));
        }
    }

    // ...
}

Проблема, с которой я сталкиваюсь при таком подходе, заключается в том, что он не очень элегантен. Мне нужно добавить эту дополнительную проверку каждой формы. Более того, этот метод не будет работать, если, скажем, запрос поступает через Zend_AMF.

Есть ли лучшие способы сделать это?

Ответы [ 3 ]

24 голосов
/ 10 января 2012

Другой вариант - заставить ваш контроллер возвращать что-то отличное от ответа и использовать событие kernel.view, чтобы преобразовать это в то, что вы хотите. Это было бы лучше СУХОЙ, потому что логика заключена в слушателе. Вам просто нужно решить, что вы хотите, чтобы ваши контроллеры возвращали.

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

И в вашем слушателе:

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()));
        }
    }
}
5 голосов
/ 11 января 2012

Вы можете вернуть ответ, как обычно, и принять решение о представлении, если вы хотите выполнить частичный рендеринг или визуализацию всей страницы, расширяя различные макеты веток.

В вашем контроллере:

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');
}

И в ваших представлениях:

{# 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>

(Возможно, вы захотите поместить часть флеш-сообщений в макрос или включение ...)

Теперь просто визуализируйте возврат изajax запрос в тег, который вы хотите разместить:

$.ajax({
  type: "POST",
  url: "tasks/new",
  data: {task: foo, dueDate: bar},
}).done(function( msg ) {
  $('#content').html(msg);
});
2 голосов
/ 06 января 2012

Пока вы можете обобщить вид ответа, необходимый для не-AJAX-форм и AJAX-форм, вы можете перевести это решение AJAX / Non-AJAX в другой метод, а затем просто иметь:

return handleResponseType(whateverInfoIsNeededToHandleIt)

После этого вы получаете полный контроль над тем, что передается вашей решающей функции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...