Liftweb: создайте форму, которую можно отправить как традиционно, так и с AJAX - PullRequest
13 голосов
/ 16 октября 2011

Возможно ли в веб-фреймворке Lift создавать формы (и ссылки), которые реагируют через AJAX, но также работают без поддержки Javascript?Если да, то как?

Когда я создаю форму, используя <lift:form.ajax>, для action формы устанавливается значение javascript://, чтобы она больше не отправлялась без JS.Если я создаю форму без явной поддержки AJAX, я не знаю, как вставить функциональность AJAX.

Полагаю, я мог бы создать интерфейс RESTful (нам все равно придется это создавать) и написать собственный Javascriptотправить форму через это.Однако я хотел бы избежать дублирования кода: если бы можно было обрабатывать все три ввода (RESTful, традиционный HTTP POST, AJAX) с одним и тем же кодом, это было бы лучше.

Ответы [ 2 ]

4 голосов
/ 12 июля 2012

Взгляните на 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>
1 голос
/ 19 апреля 2012

Я мало что знаю о Лифте, поэтому мой ответ сосредоточен на альтернативном способе сделать это. Это основано на jQuery и будет работать с AJAX, когда Javascript пригоден для использования, и традиционным POST, если не включена поддержка Javascript.

Форма:

<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.
}

?>

А как же тогда ОТДЫХ?

Это то, что вы должны решить использовать или не использовать, это не то, что нужно поддерживать в качестве альтернативы другим методам (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-вызов, который сделает все:

Вы правы, компьютеры должны делать нашу работу. Это то, для чего они предназначены.

Итак, еще одна вещь, которую нужно сделать, это проверить, какой метод http хочет использовать наша оригинальная html-форма, и адаптировать его для отправки ajax-запросов тем же методом, который будет использоваться без поддержки javascript . Это модифицированная версия из-под 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 отправляет данные в виде объекта JSON, используя метод (post | get | put | delete), который определен в <form method="put" ...>, если метод формы изменяется, тогда наш обработчик ajax также адаптирует изменения.

Вот и все, часть кода проверена и фактически используется, часть вообще не проверена, но должна работать.

...