Ajax代表异步Javascript与XML,它是转向富web应用程序的驱动力. 这些类型的应用程序,通常更适合于像Ruby和 Groovy语言所写的敏捷,动态框架,Grails通过它的Ajax标签库提供支持构建Ajax应用程序. 它们完整的列表可以参看标签库参考.
Grails默认装载Prototype 库,但通过Plug-in 系统,可以提供对Dojo, Yahoo UI 和 Google Web Toolkit 等其他框架的支持.
这部分涵盖Grails对Prototype的支持。你需要在页面的<head>
标签内添加这样一行就可以开始了 :
<g:javascript library="prototype" />
这里使用javascript标签自动插入Prototype正确位置的引用。假如你同样需要Scriptaculous ,你可以如下这样做为替换 :
<g:javascript library="scriptaculous" />
远程内容可以通过多种方式加载,最常使用的方法是通过 remoteLink 标签。 这个标签允许创建的HTML锚标记执行一个异步请求,并在一个元素中随意设置响应。用这个简单方式创建的远程链接就像这样 :
<g:remoteLink action="delete" id="1">Delete Book</g:remoteLink>
上面的连接发送一个异步请求给当前id为1
的控制器的delete
操作 .
这真是太棒了,但通常你想提供一些事情发生的反馈信息给用户:
def delete = {
def b = Book.get( params.id )
b.delete()
render "Book ${b.id} was deleted"
}
GSP代码:
<div id="message"></div> <g:remoteLink action="delete" id="1" update="message">Delete Book</g:remoteLink>
上面的示例将调用这个操作并设置message
div
的响应内容为"Book 1 was deleted"
。这通过标签上的update
属性来完成,它同样可以获取一个map来指出在失败时什么被更新 :
<div id="message"></div> <div id="error"></div> <g:remoteLink action="delete" id="1" update="[success:'message',failure:'error']">Delete Book</g:remoteLink>
这里,error
div在请求失败时被更新.
,一个HTML form也可以异步被提交通过以下两种方式之一。第一个,使用 formRemote 标签,它和 remoteLink 标签有类似的属性 :
<g:formRemote url="[controller:'book',action:'delete']" update="[success:'message',failure:'error']"> <input type="hidden" name="id" value="1" /> <input type="submit" value="Delete Book!" /> </g:formRemote >
或者作为选择可以使用submitToRemote来创建一个提交按钮。它允许一些按钮远程提交而一些不依赖操作 :
<form action="delete"> <input type="hidden" name="id" value="1" /> <g:submitToRemote action="delete" update="[success:'message',failure:'error']" /> </form>
某些事件的发生会调用特定的javascript。所有以"on"开头的事件,在适当的时候允许你反馈信息给用户,或采取其他行为:
<g:remoteLink action="show" id="1" update="success" onLoading="showProgress()" onComplete="hideProgress()">Show Book 1</g:remoteLink>
上述代码将执行"showProgress()"函数来显示一个进度条或者其他适当的展示,其他的事件还包括 :
onSuccess
- 成功时调用的javascript函数 onFailure
- 失败时调用的javascript函数 on_ERROR_CODE
- 处理指定的错误代码时调用的javascript函数 (例如 on404="alert('not found!')") onUninitialized
- 一个ajax引擎初始化失败时调用的javascript函数 onLoading
- 当远程函数加载响应时调用的javascript函数 onLoaded
- 当远程函数加载完响应时调用的javascript函数 onComplete
- 当远程函数完成(包括任何更新)时调用的javascript函数 假如你需要引用XmlHttpRequest
对象,你可以使用隐式的event参数e
获取它 :
<g:javascript> function fireMe(e) { alert("XmlHttpRequest = " + e) } } </g:javascript> <g:remoteLink action="example" update="success" onSuccess="fireMe(e)">Ajax Link</g:remoteLink>
Grails把 Dojo 作为一种外部插件来支持Grails的特性。在终端窗口,进入你项目的根目录键入下列命令来安装插件 :
grails install-plugin dojo
将下载Dojo最新的支持版本,并安装到你的Grails项目中。完成上面的步骤后,你可以在你页面的顶部添加下列引用:
<g:javascript library="dojo" />
现在,所有像remoteLink, formRemote 和 submitToRemote标签都可以和Dojo进行远程处理工作 .
Grails同样支持 Google Web Toolkit 特性,插件的全面 文档 可以在Grails wiki中找到 .
虽然Ajax特性X为XML,但通常可以分解成许多不同方式执行Ajax:
在Ajax部分中的更多的示例涵盖了内容为中心的 Ajax在什么地方更新页面,但同样你可能使用数据为中心的Ajax或脚本为中心的 Ajax。这份指南涵盖了不同风格的Ajax .
作为概括,内容为中心的 Ajax涉及从服务器端发送一些HTML返回和通过使用render方法来渲染模板 :
def showBook = { def b = Book.get(params.id)render(template:"bookTemplate", model:[book:b]) }
在客户端调用这个会涉及到remoteLink标签的使用 :
<g:remoteLink action="showBook" id="${book.id}" update="book${book.id}">Update Book</g:remoteLink> <div id="book${book.id}"> <!--existing book mark-up --> </div>
数据为中心的Ajax通常涉及到客户端响应的赋值和编程化更新。Grails中的JSON响应,通常使用Grails的JSON marshaling能力 :
import grails.converters.*def showBook = { def b = Book.get(params.id)
render b as JSON }
然后,在客户端使用一个Ajax事件处理解析这个进入的JSON请求:
<g:javascript> function updateBook(e) { var book = eval("("+e.responseText+")") // evaluate the JSON $("book"+book.id+"_title").innerHTML = book.title } <g:javascript> <g:remoteLink action="test" update="foo" onSuccess="updateBook(e)">Update Book</g:remoteLink> <g:set var="bookId">book${book.id}</g:set> <div id="${bookId}"> <div id="${bookId}_title">The Stand</div> </div>
在服务器端使用XML同样普遍:
import grails.converters.*def showBook = { def b = Book.get(params.id)
render b as XML }
不过,因为涉及到DOM,客户变得更复杂:
<g:javascript> function updateBook(e) { var xml = e.responseXML var id = xml.getElementsByTagName("book").getAttribute("id") $("book"+id+"_title")=xml.getElementsByTagName("title")[0].textContent } <g:javascript> <g:remoteLink action="test" update="foo" onSuccess="updateBook(e)">Update Book</g:remoteLink> <g:set var="bookId">book${book.id}</g:set> <div id="${bookId}"> <div id="${bookId}_title">The Stand</div> </div>
脚本为中心的 Ajax涉及实际返回的Javascript在客户端被赋值。这样的示例见下表:
def showBook = { def b = Book.get(params.id)response.contentType = "text/javascript" String title = b.title.encodeAsJavascript() render "$('book${b.id}_title')='${title}'" }
要记住的重要事情是,设置contentType
为text/javascript
。如果在客户端使用Prototype,由于设置了contentType
,返回的Javascript将自动被赋值.
很明显,在这种情况下,它是关键性的,你有一个一致的client-sideAPI,因此,你不想客户端的改变破坏服务器端。这就是Rails有些像RJS的理由之一。虽然,Grails当前没有像RJS的一个特性,但动态Dynamic JavaScript Plug-in插件提供了类似的能力.