На раннем этапе новички в Grails сталкиваются с отсутствием рабочих образцов, сопровождающих структуру. Хорошие места для примеров и документации включают документацию Grails и блогеров.
Ajax — это одна из функций со встроенной поддержкой Grails. Как только люди «осваивают» основы Grails, они обычно хотят перейти к более интересным функциям, таким как Ajax. Обычно для этого требуется прочесать сеть, найти примеры и / или прочитать документацию достаточно внимательно. Я прошел этот процесс и подумал, что другие могут получить пользу от набора коротких рабочих примеров Ajax в Grails. Я создал небольшое приложение, которое демонстрирует некоторые функции Ajax и предоставляет приложение для загрузки всем, кто заинтересован. (см внизу для скачивания
Информация)
В примере приложения используется каждое из следующего:
- FormRemote
- RemoteLink
- SubmitToRemote
- RemoteFunction
- RemoteField
Общие шаги
- Выберите свою библиотеку JavaScript — прототип, использованный в моем примере. Также показана регистрация некоторых событий Ajax.
|
01
02
03
04
05
06
07
08
09
10
11
|
function showSpinner(visible) { $('spinner').style.display = visible ? "inline" : "none"; } Ajax.Responders.register({ onLoading: function() { showSpinner(true); }, onComplete: function() { if(!Ajax.activeRequestCount) showSpinner(false); } }); |
- Обновите свой контроллер с любым необходимым кодом — ниже весь мой BookController
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
|
package ajaxclass BookController { def scaffold = true def showEditAjax = { render (view:'editAjax', model:[bookInstance:Book.get(params.id)]) } def showListSelect = { render (view:'listSelect', model:[bookInstanceList:Book.list()]) } def showTitleSearch = { render (view:'titleSearchAjax') } def showRemoteLink = { render (view:'remoteLink', model:[bookInstanceList:Book.list()]) } def showDetails = { render(template:'bookDetails', model:[bookInstance:Book.get(params.id)]) } def showSearch = { render (view:'searchAjax') } def String wrapSearchParm(value) { '%'+value+'%' } def searchTitle = { def list = Book.findAllByTitleIlike(wrapSearchParm(params.searchvalue)) render(template:'searchResults', model:[searchresults:list]) } def search = { def list if (params.publisher && params.title) list = Book.findAllByTitleIlikeAndPublisherIlike(wrapSearchParm(params.title), wrapSearchParm(params.publisher)) else if (params.publisher) list = Book.findAllByPublisherIlike(wrapSearchParm(params.publisher)) else if (params.title) list = Book.findAllByTitleIlike(wrapSearchParm(params.title)) render(template:'searchResults', model:[searchresults:list]) } def listByPublisher = { def list if (params.filter.equals("All")) list = Book.list() else list = Book.findAllByPublisher(params.filter) render(template:'searchResults', model:[searchresults:list]) } def update = { def bookInstance = Book.get( params.id ) if(bookInstance) { bookInstance.properties = params if(!bookInstance.hasErrors() && bookInstance.save()) { render " Book ${params.title} updated with Ajax using FormRemote" } else { render(view:'edit',model:[bookInstance:bookInstance]) } } else { flash.message = "Book not found with id ${params.id}" redirect(action:edit,id:params.id) } }} |
- Создать / обновить вид (ы) — см. Скриншоты ниже и / или загрузить приложение
Большинство примеров довольно просты и не требуют большого объяснения. Они не могут быть отличными примерами из «реального мира», но их цель — предоставить работающий пример для кого-то, с кого можно начать.
FormRemote
TagLib formRemote создает тег формы, который использует удаленный URI для выполнения вызова AJAX. В этом случае я немного изменил созданный по умолчанию файл edit.gsp, чтобы изменить тег формы на тег formRemote, и добавил div для отображения результатов редактирования. На приведенном ниже снимке экрана показан результат первого нажатия кнопки меню навигации Remote Form, изменения количества страниц в книге «Grails in Action» и нажатия кнопки «Обновить» в нижней части экрана.
RemoteLink
Тег RemoteLink создает ссылку, которая при нажатии вызывает удаленную функцию. В примере приложения я отображаю список названий книг, а заголовок является ссылкой. Нажатие на название показывает детали книги в нижней части экрана.
|
1
2
3
|
<g:each in="${bookInstanceList}" status="i" var="bookInstance"> <g:remotelink action="showDetails" id="${bookInstance.id}" oncomplete="showSpinner(false);" onloading="showSpinner(true);" update="bookDetails">${fieldValue(bean: bookInstance, field: "title")}</g:remotelink> </g:each> |
SubmitToRemote
Тег submitToRemote создает кнопку, которая отправляет окружающую форму в виде удаленного вызова Ajax, сериализующего поля в параметры. В примере приложения я создал поля поиска для заголовка и издателя. Кнопка поиска была создана с использованием taglib SubmitToRemote для отправки параметров поиска с помощью Ajax.
|
1
2
3
4
5
|
<g:form action="search"><table><tbody><tr class="prop"> <td class="name" valign="top">Title:</td> <td class="value" valign="top"><input name="title" value="${title}" type="text"></td> </tr><tr class="prop"> <td class="name" valign="top">Publisher:</td> <td class="value" valign="top"><input name="publisher" value="${publisher}" type="text"></td> </tr></tbody> </table><g:submittoremote oncomplete="showSpinner(false)" onloading="showSpinner(true)" update="searchresults" url="[controller:'book', action:'search']" value="Search"></g:submittoremote></g:form> |
RemoteFunction
Пример приложения использует тег tag Remotebunction для создания удаленной функции JavaScript, которая назначается событию onChange DOM. Когда пользователь выбирает или изменяет значение в раскрывающемся списке «Издатель», вызывается удаленная функция, и в нижней половине экрана отображаются книги, опубликованные выбранным издателем.
RemoteField
В примере приложения используется тег тега RemoteField для создания динамического поиска по названиям книг, аналогично Google Instant. Результаты поиска возвращаются на экран при вводе значений в поле Поиск заголовка. Код контроллера в этом случае оборачивает параметр поиска символом подстановки (%) для поиска в базе данных и возвращает все совпадения, которые будут отображены.
|
1
2
3
|
<div id="searchbox">Title Search:<g:remotefield name="search" oncomplete="showSpinner(false);" onloading="showSpinner(true);" paramname="searchvalue" update="searchresults" url="[controller:'book', action:'searchTitle']"></g:remotefield></div> |
Обнаруженные проблемы
- Я столкнулся с проблемами, пытаясь заставить корректно показывать счетчик, пока не нашел эту запись в StackOverflow, которая показывала, как регистрировать события Ajax. При локальном запуске в том же окне это происходит очень быстро, поэтому вам действительно нужно следить за правым верхним углом экрана, если вы хотите увидеть счетчик.
- Я также столкнулся с проблемами с RemoteFunction из-за синтаксических проблем. Будучи привыкшим к тегам тегов, я устанавливал параметр обновления, используя update = ”mydiv”, когда синтаксис должен был обновляться: “mydiv”. Это не помечено как ошибка. Контроллер был вызван, он просто не обновил целевой div!
Загрузки
- Скачайте zip здесь
- Получить копию с Github — это моя первая попытка создать репозиторий на Github, поэтому, если я сделал это неправильно, пожалуйста, дайте мне знать.
Было весело собрать это вместе. Надеюсь, это поможет некоторым из вас!




