Подтвердить что ты не робот

Liftweb: создать форму, которая может быть представлена ​​как традиционно, так и с помощью AJAX

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

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

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

4b9b3361

Ответ 1

Взгляните на 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>

Ответ 2

Я не очень много знаю о Lift, поэтому мой ответ фокусируется на альтернативном способе сделать это. Это 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:

note: 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, который делает все:

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

Итак, еще одна вещь, которая должна быть выполнена, - проверить, какой метод 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 также будет адаптировать изменения.

Что все, какой-то код протестирован и на самом деле используется, некоторые не тестируются вообще, но должны работать.