Złożenie formularza Ajax w symfony2 z gracją degradacji dla użytkowników bez javascript
Buduję aplikację internetową, która zawiera formularze. Używany framework to symfony2. Chciałbym, aby wszystko działało dla użytkowników bez javascript, a następnie stopniowo zwiększać doświadczenie dla osób z włączoną obsługą javascript. Planuję użyć JQuery jako mojej biblioteki javascript.
Chciałbym mieć formularze, w których wysyła i wyświetla wiadomość za pomocą komponentu FlashMessage, jeśli użytkownik nie ma javascript i żądanie nie jest Ajaxem Prośba.
Dla użytkowników z obsługą javascript, chciałbym zwrócić wiadomość do nich, jeśli zgłoszenie się powiedzie. Następnie javascript powinien natychmiast wyświetlić tę wiadomość w div.
W tym samym czasie, muszę radzić sobie z komunikatami o błędach. Dla użytkowników bez javascript, cały formularz zostanie ponownie wysłany z komunikatami o błędach w miejscu.
Dla użytkowników z javascript, odpowiedź ajax powinna być tablicą zawierającą id komponentu input i Komunikat o błędzie. Javascript powinien następnie wstawić je do formularza bez odświeżania.
Patrząc na Księgę symfony2, widzę, co następuje dla zgłoszeń, następnie zmodyfikowałem ją, aby sprawdzić, czy żądanie jest żądaniem 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'));
}
}
// ...
}
Problem, który znajduję w tym podejściu jest to, że nie jest zbyt elegancki. Muszę dodać ten dodatkowy czek w każdym formularzu. Co więcej, ta metoda nie będzie działać, jeśli powiedzmy, że żądanie przychodzi przez Zend_AMF.
Czy są na to jakieś lepsze sposoby?3 answers
Inną opcją jest zwrócenie przez kontroler czegoś innego niż odpowiedź i użycie zdarzenia kernel.view
do przekształcenia tego w to, co chcesz. Byłoby to lepiej suche, ponieważ logika jest zamknięta w słuchaczu. Musisz tylko zdecydować, co chcesz, aby Twoje Kontrolery zwróciły.
if ($form->isValid()) {
return new Something($redirectUrl, $ajaxData);
}
I w Twoim słuchaczu:
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()));
}
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-10 15:09:23
Możesz zwrócić odpowiedź jak zwykle i zdecydować, czy chcesz wykonać częściowe renderowanie lub renderować całą stronę, rozszerzając różne układy gałązek.
W Twoim kontrolerze:
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');
}
I w Twoich poglądach:
{# 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>
(możesz umieścić część wiadomości flash w makrze lub nagłówku...)
Teraz po prostu wyrenderuj zwrot z żądania ajax do znacznika, który chcesz umieścić:
$.ajax({
type: "POST",
url: "tasks/new",
data: {task: foo, dueDate: bar},
}).done(function( msg ) {
$('#content').html(msg);
});
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-11 12:48:22
Tak długo, jak można uogólnić rodzaj odpowiedzi potrzebnej dla formularzy innych niż ajax i dla formularzy ajax, można przenieść tę decyzję ajax / non-ajax do innej metody, a następnie po prostu mieć:
return handleResponseType(whateverInfoIsNeededToHandleIt)
Wtedy masz pełną kontrolę nad tym, co przechodzi do Twojej decydującej funkcji.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-06 17:30:40