Xitrum提供了Ajax表单回发功能以支持 创建交互式的web页面
Xitrum的回发机制受了Nitrogen Web Framework的启发。
//AppAction.scala
import xitrum.Action
import xitrum.view.DocType
trait postbackTest extends Action {
override def layout = DocType.html5(
<html>
<head>
{antiCsrfMeta}
<script type="text/javascript" src="/test/js/jquery.js"></script>
<script type="text/javascript" src="/test/js/jquery.validate.js"></script>
<script type="text/javascript" src="/test/js/additional-methods.js"></script>
<script type="text/javascript" src="/test/js/sockjs.js"></script>
<script type="text/javascript" src="/xitrum/xitrum-3.28.3.js"></script>
<title>Test PostBack</title>
</head>
<body>
{renderedView}
{jsForView}
</body>
</html>
)
}
//Form
//Articles.scala
import xitrum.annotation.{GET, POST, First}
import xitrum.validator._
@GET("test/articles/:id")
class ArticlesShow extends postbackTest{
def execute(){
val id = param[Int]("id")
val article = Article.find(id)
respondInlineView(
<h1>{article.get.title}</h1>
<div>{article.get.body}</div>
)
}
}
@First // Force this route to be matched before "show"
@GET("test/articles/new")
class ArticlesNew extends postbackTest{
def execute(){
respondInlineView(
//如果没有data-postback设置,点击Save后的URL地址就是http://localhost:8001/test/articles?title=a3&body=b3
//因为不符合已有的route而进入404.html
//设置data-postback后,url不会显示数据内容,且最终跳转到 http://localhost:8001/test/articles/3
<form data-postback="submit" action={url[ArticlesCreate]}>
<label>Title</label>
<input type="text" name="title" class="required" /><br />
<label>Body</label>
<textarea name="body" class="required"></textarea><br />
<input type="submit" value="Save" />
</form>
)
}
}
@POST("test/articles")
class ArticlesCreate extends postbackTest{
def execute(){
val title = param("title")
val body = param("body")
val article = Article.save(title, body)
flash("Article has been saved.")
jsRedirectTo[ArticlesShow]("id" → article.id)
}
}
case class Article(id: Int,
title: String = "article title", body: String = "article body"){
}
object Article{
private var storage = Map[Int, Article]()
private var nextId = 1
def findAll(): Iterable[Article] = storage.values
def find(id: Int): Option[Article] = storage.get(id)
def save(title: String, body: String): Article = synchronized {
val article2 = Article(nextId, title, body)
storage = storage + (nextId → article2)
nextId += 1
article2
}
save("a1", "b1")
save("a2", "b2")
}
当form的submit事件被触发时,form会回发到ArticlesCreate。form的action的属性值会被加密。
回发可以被放到任何element上,不仅是form。放到链接上的示例:
<a href="#" data-postback="click"
action={url[LogoutAction]}
data-confirm="Do you wang to logout?"
>Logout</a> <!-- 点击链接会弹出确认窗口,Cancel就不会触发回发,否则就会触发回发到LogoutAction -->
有postback的元素的action所指向的Action的route一定要用post。
在这个例子中,我刻意把action的设置去掉后,点击确认按钮后,在Chrome“检查”>“Network”中,发现jquery.js中报出的错误。应该提供的是jquery的postback。
附加参数
1. 对于表单form元素,可以通过添加隐藏的input,如<input type="hidden" ...>,来在回发时传递附加参数
2. 对于其他元素可以使用data-params来传递附加参数
<!--For other elements, you do like this:--> <a href="#" data-postback="click"
action={url[ArticlesDestroy]("id" -> item.id)} data-params="_method=delete" data-confirm={"Do you want to delete %s?".format(item.name)}>Delete</a>
3. 把附加参数放在一个单独的form中
<!--You may also put extra params in a separate form:--> <form id="myform" data-postback="submit" action={url[SiteSearch]}> Search: <input type="text" name="keyword" /> <a class="pagination" href="#" data-postback="click" data-form="#myform" action={url[SiteSearch]("page" -> page)}>{page}</a> </form>
#myform是一个jQuery选择器用来定位包含额外参数的form
自定义Ajax加载动画
默认的加载动画是
src="/webjars/xitrum/3.28.3/ajax.gif?SIl4RonBuBCfl6Duz5Jl9A"
要自定义加载动画的话,在View模板中的jsDefaults后面调用以下JS片段
// target: The element that triggered the postback xitrum.ajaxLoading = function(target) { // Called when the animation should be displayed when the Ajax postback is being sent. var show = function() { ...
// Display Ajax loading animation image
target.after('<img id="' + ajaxLoadingImgId + '" src="""" + 自定义动画 + """" />');
}; // Called when the animation should be stopped after the Ajax postback completes. var hide = function() { ... }; return {show: show, hide: hide}; };