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

发布于 2024-12-10 07:54:52 字数 1322 浏览 1 评论 0原文

我正在构建一个涉及表单的网络应用程序。使用的框架是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 传入,则此方法将不起作用。

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

I am building a web application that involves forms. The framework being used is symfony2. I would like to have everything working for users without javascript, and then progressively enhance the experience for people with javascript enabled. I am planning to use JQuery as my javascript library.

I would like to have forms where it submits and displays a message using the FlashMessage component if the user does not have javascript and the request is not an ajax request.

For users with javascript support, I would like to return the message to them if submission is successful. The javascript should then display that message in a div immediately.

At the same time, I need to deal with error messages. For users without javascript, the whole form will be rerendered with the error messages in place.

For users with javascript, the ajax response should be an array containing the id of the input component and the error message. Javascript should then insert these into the form without a refresh.

Looking at the symfony2 book, I can see the following for submissions, I then modified it to check if the request is an ajax request:

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

    // ...
}

The problem I find with this approach is that is isn't very elegant. I need add that extra check every single form. Further more, this method would not work if say the request comes in via Zend_AMF.

Are there any better ways to do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

撩起发的微风 2024-12-17 07:54:52

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

Another option is to have your controller return something other than a response and use the kernel.view event to transform that into what you want. This would be better DRY because the logic is encapsulated in the listener. You just need to decide what you want your controllers to return.

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

And in your listener:

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()));
        }
    }
}
纵情客 2024-12-17 07:54:52

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

在你的控制器中:

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

You can return a response like usual and decide on the view if you want to do a partial render or render the whole page by extending different twig layouts.

In your controller:

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

And in your views:

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

(You might want to put the flash messages part in a macro or an include...)

Now simply render the return from the ajax request into the tag you want to place it:

$.ajax({
  type: "POST",
  url: "tasks/new",
  data: {task: foo, dueDate: bar},
}).done(function( msg ) {
  $('#content').html(msg);
});
っ左 2024-12-17 07:54:52

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

return handleResponseType(whateverInfoIsNeededToHandleIt)

您就可以完全控制传入的内容到你的决定功能。

As long as you can generalize the sort of response needed for non-ajax forms and for ajax forms, you can relegate that decision of ajax/non-ajax to another method and then simply have:

return handleResponseType(whateverInfoIsNeededToHandleIt)

You then have full control over what gets passed in to your deciding function.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文