2011-10-16 45 views
14

我正在構建一個涉及表單的Web應用程序。正在使用的框架是symfony2。我想讓沒有javascript的用戶都能正常工作,然後逐漸增強啓用javascript的用戶的體驗。我打算使用JQuery作爲我的JavaScript庫。在symfony2中爲Ajax表單提交的優雅降級,無需javascript的用戶

我想要使用FlashMessage組件提交併顯示消息的表單,如果用戶沒有javascript並且請求不是ajax請求。

對於支持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')); 
     } 
    } 

    // ... 
} 

我發現這種方法的問題是ISN非常優雅。我需要添加額外的檢查每一種形式。此外,如果說通過Zend_AMF發送請求,這個方法將不起作用。

有沒有更好的方法來做到這一點?

回答

24

另一種選擇是讓您的控制器返回響應以外的內容並使用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())); 
     } 
    } 
} 
2

只要你能概括的排序需要非Ajax形式和阿賈克斯形式的反應,你可以貶謫AJAX的這一決定/非Ajax另一種方法,然後只需:

return handleResponseType(whateverInfoIsNeededToHandleIt) 

然後,您可以完全控制傳遞給您的決定功能的內容。

5

您可以返回像往常一樣的迴應,如果你想要做一個局部渲染或通過擴展不同的樹枝佈局使整個頁面上的觀點決定。

在你的控制器:

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