Liftweb: создать форму, которая может быть представлена как традиционно, так и с помощью AJAX
Возможно ли в веб-фреймворке Lift создавать формы (и ссылки), которые реагируют через AJAX, но также работают без поддержки Javascript? Если да, то как?
Когда я создаю форму с помощью <lift:form.ajax>
, форма action
устанавливается на javascript://
, так что она больше не отправляет без JS. Если я создам форму без явной поддержки AJAX, я не знаю, как вставить функциональность AJAX.
Я полагаю, что я мог бы создать интерфейс RESTful (мы все равно его построим) и написать собственный Javascript, чтобы отправить форму через это. Однако я хотел бы избежать дублирования кода: если можно обрабатывать все три входа (RESTful, традиционный HTTP POST, AJAX) с тем же кодом, это было бы лучше.
Ответы
Ответ 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 также будет адаптировать изменения.
Что все, какой-то код протестирован и на самом деле используется, некоторые не тестируются вообще, но должны работать.