Liftweb:创建一个可以通过传统方式和 AJAX 提交的表单

发布于 2024-12-10 08:26:23 字数 400 浏览 0 评论 0原文

Lift Web 框架是否可以创建通过 AJAX 做出反应的表单(和链接),但也可以在没有 Javascript 支持的情况下工作?如果是这样,怎么办?

当我使用 构建表单时,表单的 action 设置为 javascript://,因此它不会不再需要 JS 提交。如果我在没有显式 AJAX 支持的情况下构建表单,我不知道如何插入 AJAX 功能。

我想我可以构建一个 RESTful 接口(无论如何我们都必须构建它)并编写自定义 Javascript 来通过该接口提交表单。不过,我想避免代码重复:如果可以使用相同的代码处理所有三个输入(RESTful、传统 HTTP POST、AJAX),那就最好了。

Is it possible in Lift web framework to create forms (and links) that react via AJAX, but also work without Javascript support? If so, how?

When I build the form using <lift:form.ajax>, the form's action is set to javascript:// so that it no longer submits without JS. If I build the form without explicit AJAX support, I don't know how to insert the AJAX functionality.

I suppose I could build a RESTful interface (we'll have to build that anyway) and write custom Javascript to submit the form through that. I would like to avoid code duplication, though: if it is possible to handle all three inputs (RESTful, traditional HTTP POST, AJAX) with the same code, that would be best.

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

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

发布评论

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

评论(2

如果没结果 2024-12-17 08:26:23

看看 http://demo.liftweb.net/form_ajax

FormWithAjax.scala

class FormWithAjax extends StatefulSnippet {
   private var firstName = ""
   private var lastName = ""
   private val from = S.referer openOr "/"

def dispatch = {
   case _ => render _
}

def render(xhtml: NodeSeq): NodeSeq =
{
   def validate() {
      (firstName.length, lastName.length) match {
         case (f, n) if f < 2 && n < 2 => S.error("First and last names too short")
         case (f, _) if f < 2 => S.error("First name too short")
         case (_, n) if n < 2 => S.error("Last name too short")
         case _ => S.notice("Thanks!"); S.redirectTo(from)
      }
   }

   bind( "form", xhtml, 
      "first" -> textAjaxTest(firstName, s => firstName = s, s => {S.notice("First name "+s); Noop}),
      "last" -> textAjaxTest(lastName, s => lastName = s, s => {S.notice("Last name "+s); Noop}),
      "submit" -> submit("Send", validate _)
   )
}

form_ajax.html

<lift:surround with="default" at="content">
  Enter your first and last name:<br>
  <form class="lift:FormWithAjax?form=post">
      First Name: <form:first></form:first>
      Last Name: <form:last></form:last>
      <form:submit></form:submit>
   </form>
</lift:surround>

这将在没有 JavaScript 的情况下工作:

<form action="/form_ajax" method="post">
   <input name="F1069091373793VHXH01" type="hidden" value="true">
   First Name: <input value="" type="text" name="F1069091373788OVAAWQ" onblur="liftAjax.lift_ajaxHandler('F1069091373789N2AO0C=' + encodeURIComponent(this.value), null, null, null)">
   Last Name: <input value="" type="text" name="F1069091373790VANYVT" onblur="liftAjax.lift_ajaxHandler('F1069091373791CJMQDY=' + encodeURIComponent(this.value), null, null, null)">
   <input name="F1069091383792JGBYWE" type="submit" value="Send">
</form>

Take a look at http://demo.liftweb.net/form_ajax

FormWithAjax.scala

class FormWithAjax extends StatefulSnippet {
   private var firstName = ""
   private var lastName = ""
   private val from = S.referer openOr "/"

def dispatch = {
   case _ => render _
}

def render(xhtml: NodeSeq): NodeSeq =
{
   def validate() {
      (firstName.length, lastName.length) match {
         case (f, n) if f < 2 && n < 2 => S.error("First and last names too short")
         case (f, _) if f < 2 => S.error("First name too short")
         case (_, n) if n < 2 => S.error("Last name too short")
         case _ => S.notice("Thanks!"); S.redirectTo(from)
      }
   }

   bind( "form", xhtml, 
      "first" -> textAjaxTest(firstName, s => firstName = s, s => {S.notice("First name "+s); Noop}),
      "last" -> textAjaxTest(lastName, s => lastName = s, s => {S.notice("Last name "+s); Noop}),
      "submit" -> submit("Send", validate _)
   )
}

form_ajax.html

<lift:surround with="default" at="content">
  Enter your first and last name:<br>
  <form class="lift:FormWithAjax?form=post">
      First Name: <form:first></form:first>
      Last Name: <form:last></form:last>
      <form:submit></form:submit>
   </form>
</lift:surround>

And this will work without javascript:

<form action="/form_ajax" method="post">
   <input name="F1069091373793VHXH01" type="hidden" value="true">
   First Name: <input value="" type="text" name="F1069091373788OVAAWQ" onblur="liftAjax.lift_ajaxHandler('F1069091373789N2AO0C=' + encodeURIComponent(this.value), null, null, null)">
   Last Name: <input value="" type="text" name="F1069091373790VANYVT" onblur="liftAjax.lift_ajaxHandler('F1069091373791CJMQDY=' + encodeURIComponent(this.value), null, null, null)">
   <input name="F1069091383792JGBYWE" type="submit" value="Send">
</form>
遇见了你 2024-12-17 08:26:23

我对 Lift 不太了解,所以我的回答重点是替代方法。
这是基于 jQuery 的,当 Javascript 可用时将使用 AJAX,如果没有启用 Javascript 支持,则将使用传统的 POST。

表单:

<form id="ajaxform" action="formhandler.php" method="post" enctype="multipart/form-data" >

<input name="firstname" type="text" />
<input name="email" type="email" />
<input name="accept" type="submit" value="Send" />

</form>

<div id="result"></div>

JS:

注意:jQuery $.ajax() 默认发送为 application/x-www-form-urlencoded,设置表单 可能会更好enctype="application/x-www-form-urlencoded" 也是如此。

$("#ajaxform").submit(function(e){

  // Alternative way to prevent default action:
  e.preventDefault();

  $.ajax({
    type: 'POST',
    url: 'formhandler.php',
    // Add method=ajax so in server side we can check if ajax is used instead of traditional post:
    data: $("#ajaxform").serialize()+"&method=ajax",
    success: function(data){ // formhandler.php returned some data:
      // Place returned data <div id="result">here</div>
      $("#result").html(data);
    }
  });

  // Prevent default action (reposting form without ajax):
  return false;
});

服务器端(PHP)

<?php

if (isset($_POST['method']) && $_POST['method'] == 'ajax') {
  // AJAX is used this time, only #result div is updating in this case.
} else {
  // Traditional POST is used to send data, whole page is reloading. Maybe send <html><head>... etc.
}

?>

那么 REST 呢?

这是您应该决定使用或不使用的东西,它不是作为其他方法(ajax、传统)的替代方法来支持的,而是更多地集成在其他方法中。
当然,您始终可以启用或禁用 REST 功能。
您始终可以使表单 method="POST/GET/PUT/DELETE" 和 ajax 调用 RESTful:

...
  $.ajax({
    type: 'PUT',
    url: 'formhandler.php',
...

...
  $.ajax({
    type: 'DELETE',
    url: 'formhandler.php',
...

但是 REST 要求我们使用 XML、JSON...来请求

,这不太好浏览器支持(无 Javascript),但 $.ajax() 使用 application/x-www-form-urlencoded 作为默认编码。

当然,使用 Javascript,我们总是可以将数据容器转换为 XML 或 JSON ...
以下是如何使用 jQuery、JSON 对象来完成此操作:

/* This is function that converts elements to JSON object,
 * $.fn. is used to add new jQuery plugin serializeObject() */
$.fn.serializeObject = function()
{
   var o = {};
   var a = this.serializeArray();
   $.each(a, function() {
       if (o[this.name]) {
           if (!o[this.name].push) {
               o[this.name] = [o[this.name]];
           }
           o[this.name].push(this.value || '');
       } else {
           o[this.name] = this.value || '';
       }
   });
   return o;
};

但我想要一个 AJAX 调用来完成所有事情:

你是对的,计算机应该完成我们的工作。这就是它们的设计目的。

因此,需要做的另一件事是检查我们的原始 html 表单想要使用哪种 http 方法,并对其进行调整,以使用与没有 javascript 支持时使用的相同方法发送 ajax 请求。
这是之前使用的 JS: 标题下的修改版本:

...
  // Alternative way to prevent default action:
  e.preventDefault();

  // Find out what is method that form wants to use and clone it:
  var restmethod = $('#ajaxform').attr('method');

  // Put form data inside JSON object:
  var data = $('#orderform').serializeObject();
  // Add method=ajax so in server side we can check if ajax is used instead of traditional post:
  data.method = 'ajax';

  $.ajax({
    type: restmethod, // Use method="delete" for ajax if so defined in <form ...>
    url: 'formhandler.php',
    data: data, // data is already serialized as JSON object
...

现在,我们的 AJAX 处理程序使用定义的方法 (post|get|put|delete) 将数据作为 JSON 对象发送在

处,如果表单方法发生更改,那么我们的 ajax 处理程序也会适应更改。

就是这样,一些代码已经过测试并且正在实际使用,有些代码根本没有经过测试但应该可以工作。

I dont know a lot about Lift so my answer focuses on alternate way to do it.
This is jQuery based and will do with AJAX when Javascript is usable and traditional POST if there is no Javascript support enabled.

Form:

<form id="ajaxform" action="formhandler.php" method="post" enctype="multipart/form-data" >

<input name="firstname" type="text" />
<input name="email" type="email" />
<input name="accept" type="submit" value="Send" />

</form>

<div id="result"></div>

JS:

note: jQuery $.ajax() sends as application/x-www-form-urlencoded by default, it may be good to set form enctype="application/x-www-form-urlencoded" too.

$("#ajaxform").submit(function(e){

  // Alternative way to prevent default action:
  e.preventDefault();

  $.ajax({
    type: 'POST',
    url: 'formhandler.php',
    // Add method=ajax so in server side we can check if ajax is used instead of traditional post:
    data: $("#ajaxform").serialize()+"&method=ajax",
    success: function(data){ // formhandler.php returned some data:
      // Place returned data <div id="result">here</div>
      $("#result").html(data);
    }
  });

  // Prevent default action (reposting form without ajax):
  return false;
});

Server side (PHP)

<?php

if (isset($_POST['method']) && $_POST['method'] == 'ajax') {
  // AJAX is used this time, only #result div is updating in this case.
} else {
  // Traditional POST is used to send data, whole page is reloading. Maybe send <html><head>... etc.
}

?>

What About REST then?

This is something you should decide to use or to not use, it is not something to support as alternate to other methods (ajax, traditional) but more something integrate within other methods.
Of course you can always enable or disable REST feature.
You can always make form method="POST/GET/PUT/DELETE" and ajax call RESTful:

...
  $.ajax({
    type: 'PUT',
    url: 'formhandler.php',
...

...
  $.ajax({
    type: 'DELETE',
    url: 'formhandler.php',
...

But REST asks us to use XML, JSON, ... for requests too

Well, that is not well supported by browsers (without Javascript) but $.ajax() uses application/x-www-form-urlencoded as default encoding.

Ofcourse, with Javascript one can always convert data container to XML or JSON ...
Here's how it can be done with jQuery, JSON object:

/* This is function that converts elements to JSON object,
 * $.fn. is used to add new jQuery plugin serializeObject() */
$.fn.serializeObject = function()
{
   var o = {};
   var a = this.serializeArray();
   $.each(a, function() {
       if (o[this.name]) {
           if (!o[this.name].push) {
               o[this.name] = [o[this.name]];
           }
           o[this.name].push(this.value || '');
       } else {
           o[this.name] = this.value || '';
       }
   });
   return o;
};

But I want one AJAX call that does everything:

You are right, computers should do our work. It's what they are designed for.

So, another thing that needs to be done is to check what http method our original html form wants to use and adapt it to send ajax requests with same method that would be used without javascript support.
This is modified version from under JS: heading used earlier:

...
  // Alternative way to prevent default action:
  e.preventDefault();

  // Find out what is method that form wants to use and clone it:
  var restmethod = $('#ajaxform').attr('method');

  // Put form data inside JSON object:
  var data = $('#orderform').serializeObject();
  // Add method=ajax so in server side we can check if ajax is used instead of traditional post:
  data.method = 'ajax';

  $.ajax({
    type: restmethod, // Use method="delete" for ajax if so defined in <form ...>
    url: 'formhandler.php',
    data: data, // data is already serialized as JSON object
...

Now, our AJAX handler sends data as JSON object using method (post|get|put|delete) that is defined at <form method="put" ...>, if form method changes then our ajax handler will adapt changes too.

That's all, some code tested and is actually in use, some is not tested at all but should work.

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