symfony2 中的 Ajax 表单提交,为没有 javascript 的用户提供优雅的降级

Posted

技术标签:

【中文标题】symfony2 中的 Ajax 表单提交,为没有 javascript 的用户提供优雅的降级【英文标题】:Ajax form submission in symfony2 with graceful degradation for users without javascript 【发布时间】:2011-12-08 15:44:24 【问题描述】:

我正在构建一个涉及表单的 Web 应用程序。使用的框架是 symfony2。我想让一切都为没有 javascript 的用户工作,然后逐步增强启用 javascript 的用户的体验。我打算使用 JQuery 作为我的 javascript 库。

如果用户没有 javascript 并且请求不是 ajax 请求,我希望使用 FlashMessage 组件提交和显示消息的表单。

对于支持javascript的用户,如果提交成功,我想将消息返回给他们。然后,javascript 应该立即在 div 中显示该消息。

同时,我需要处理错误信息。对于没有 javascript 的用户,整个表单将重新呈现并显示错误消息。

对于使用 javascript 的用户,ajax 响应应该是一个数组,其中包含输入组件的 id 和错误消息。然后 Javascript 应该将这些插入到表单中而无需刷新。

查看symfony2 book,我可以看到以下提交,然后我修改它以检查请求是否为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 进来的,这种方法将不起作用。

有没有更好的方法来做到这一点?

【问题讨论】:

【参考方案1】:

另一种选择是让您的控制器返回响应以外的其他内容,并使用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()));
        
    

【讨论】:

【参考方案2】:

您可以像往常一样返回响应,并决定是要进行部分渲染还是通过扩展不同的树枝布局来渲染整个页面。

在您的控制器中:

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

【讨论】:

【参考方案3】:

只要您可以概括非 ajax 表单和 ajax 表单所需的响应类型,您就可以将 ajax/非 ajax 的决定委托给另一种方法,然后只需:

return handleResponseType(whateverInfoIsNeededToHandleIt)

然后,您可以完全控制传递给您的决定功能的内容。

【讨论】:

以上是关于symfony2 中的 Ajax 表单提交,为没有 javascript 的用户提供优雅的降级的主要内容,如果未能解决你的问题,请参考以下文章

在 ajax 提交时禁用 symfony 2 csrf 令牌保护

Symfony2:使用 ajax 和验证更改选择

使用Ajax(无表单)将POST数据以JSON格式发送到Symfony2 Controller

Rails 5 ajax 表单:单击 Ajax 中的 2 个单选按钮之一提交表单

Symfony2 防止多个表单提交

带有 CSRF 的 Symfony2 表单通过 JQuery AJAX 传递