[英]Ajax form submission in symfony2 with graceful degradation for users without javascript
我正在構建一個涉及表單的Web應用程序。 正在使用的框架是symfony2。 我想讓一切為沒有javascript的用戶工作,然后逐步增強啟用javascript的人的體驗。 我打算用JQuery作為我的javascript庫。
如果用戶沒有javascript並且請求不是ajax請求,我希望有提交的表單並使用FlashMessage組件顯示消息。
對於具有javascript支持的用戶,如果提交成功,我想將消息返回給他們。 然后,javascript應立即在div中顯示該消息。
與此同時,我需要處理錯誤消息。 對於沒有javascript的用戶,整個表單將被重新呈現,並顯示錯誤消息。
對於使用javascript的用戶,ajax響應應該是一個包含輸入組件的id和錯誤消息的數組。 然后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進入,則此方法不起作用。
有沒有更好的方法來做到這一點?
另一個選擇是讓控制器返回響應以外的內容,並使用kernel.view
事件將其轉換為您想要的內容。 這將是更好的DRY,因為邏輯被封裝在監聽器中。 您只需要決定控制器要返回的內容。
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()));
}
}
}
您可以像往常一樣返回響應並決定視圖是否要通過擴展不同的樹枝布局來進行部分渲染或渲染整個頁面。
在你的控制器中:
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>
(您可能希望將Flash消息部分放在宏或包含...中)
現在只需將ajax請求的返回值渲染到要放置的標記中:
$.ajax({
type: "POST",
url: "tasks/new",
data: {task: foo, dueDate: bar},
}).done(function( msg ) {
$('#content').html(msg);
});
只要您可以概括非ajax表單和ajax表單所需的響應類型,您可以將ajax / non-ajax的決定權轉移到另一個方法,然后只需:
return handleResponseType(whateverInfoIsNeededToHandleIt)
然后,您可以完全控制傳遞給決策函數的內容。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.