Einführung
Wir beginnen mit der Erstellung einer einfachen privaten Bibliothek, in der der Benutzer Autoren, Bücher und Buchexemplare anlegen kann (inspiriert von dem zuvor unter „Nutzung“ beschriebenen Projekt).
Wir haben in myLibrary bereits einigen Code für Sie implementiert. Für dieses Tutorial haben Sie zwei Möglichkeiten: Sie können entweder der hier bereitgestellten Schritt-für-Schritt-Implementierung folgen oder versuchen, jeden Schritt zuerst selbst zu implementieren und Ihre Implementierung anschließend zu überprüfen. Die Erklärung jeder Methode ist zwischen dieser Dokumentation und myLibrary aufgeteilt.
Pro-Modus: Ein anspruchsvollerer Modus für erfahrene Benutzer. Sie werden ermutigt, die Implementierungen selbstständig zu versuchen und nur bei Bedarf auf die bereitgestellten Beispiele zurückzugreifen.
Einrichtung
Die Lösung und die Grundgerüste für diese Aufgabe können aus diesem Repository geklont werden:
git clone git@github.com:Taack/myLibrary.git
cd in das Projekt (myLibrary) und kopieren Sie die folgende Zeile.git checkout part-1-skeleton
Oder Sie wählen in IntelliJ direkt den gewünschten Branch aus. Wählen Sie oben links main/myLibrary/remote, um alle Branches anzuzeigen. Wählen Sie einen Branch aus und führen Sie „Checkout“ aus.
Hinweis: Für jede TODO-Implementierung wurde zu Ihrer Erleichterung ein neuer Branch angelegt. Falls etwas schiefgeht, können Sie jederzeit zu diesem Branch wechseln, anstatt von vorne zu beginnen. Hinweis: Beispielsweise ist in part-1-todo-4 das TODO 4 bereits für Sie implementiert.
part-1-todo-4 fortsetzen möchten, gehen Sie wie folgt vor.git checkout part-1-todo-4
Domänenklassen definieren
Bearbeiten: app/library/src/main/groovy/myLibrary/domain/
Pro-Modus: Implementieren Sie jede Klasse selbst. Alle erforderlichen Informationen befinden sich in der Datei. Überprüfen Sie nach der Implementierung von MyLibraryAuthor, MyLibraryBook und MyLibraryBookInstance Ihre Lösung hier. [TODO 1.1, 1.2 & 1.3]
MyLibraryAuthor (TODO 1.1):import grails.compiler.GrailsCompileStatic
import taack.ast.annotation.TaackFieldEnum
@GrailsCompileStatic
@TaackFieldEnum
class MyLibraryAuthor {
String firstName
String lastName
Date dateOfBirth
List<MyLibraryBook> listOfBooks //(1)
Boolean isActive = true //(2)
static constraints = {}
static hasMany = [listOfBooks: MyLibraryBook] //(3)
String toString() {
return firstName + ' ' + lastName
}
}
-
Books, die von diesemAuthorgeschrieben wurden, werden inlistOfBooksgespeichert. -
isActiveermöglicht das logische Löschen (Soft Delete). -
hasManyist ein GORM-Assoziationsschlüsselwort, mit dem wir eine Eins-zu-viele-Beziehung zwischen Domänenklassen definieren können. Es wird verwendet, um zugehörige Sammlungen (wie eine Liste von Büchern, die zu einem Autor gehören) automatisch zu verwalten. Weitere Informationen finden Sie in der GORM-Dokumentation.
MyLibraryBook (TODO 1.2):import grails.compiler.GrailsCompileStatic
import taack.ast.annotation.TaackFieldEnum
@GrailsCompileStatic
@TaackFieldEnum
class MyLibraryBook {
String title
MyLibraryAuthor author
String description
int numberOfPages
List<MyLibraryBookInstance> listOfBookInstance //(1)
int count = 0
static constraints = {}
static hasMany = [listOfBookInstance: MyLibraryBookInstance]
int getNumberOfInstances() {
if (!listOfBookInstance) { return 0}
count = listOfBookInstance.count {it.isActive} as int
return count
}
}
-
BookInstancesdiesesBookwerden inlistOfBookInstancegespeichert.
MyLibraryBookInstance (TODO 1.3):import grails.compiler.GrailsCompileStatic
import taack.ast.annotation.TaackFieldEnum
@GrailsCompileStatic
@TaackFieldEnum
class MyLibraryBookInstance {
MyLibraryBook book
Boolean isActive = true
Integer serialNumber = new Random().nextInt(100000) //(1)
static constraints = {}
static belongsTo = [book: MyLibraryBook] //(2)
}
-
Random().nextInt(100000)erzeugt eine Zufallszahl zwischen 0 und 100 000. -
belongsToist ein GORM-Assoziationsschlüsselwort, das die besitzende Seite einer Viele-zu-eins-Beziehung zwischen Domänenklassen definiert. Es verwaltet automatisch die Fremdschlüsselverknüpfung und das Kaskadierungsverhalten (z. B. gehört jedes Buch zu einem einzelnen Autor). Weitere Informationen finden Sie in der GORM-Dokumentation.
Sie haben nun alle erforderlichen Klassen für diesen Abschnitt erstellt!
Wechseln Sie zu src/main/groovy/mylibrary.
NumberForInstances:import grails.compiler.GrailsCompileStatic
import grails.validation.Validateable
import taack.ast.annotation.TaackFieldEnum
@TaackFieldEnum
@GrailsCompileStatic
class NumberForInstances implements Validateable {
Integer numberOfInstances
}
Hier gibt es nichts zu implementieren. Diese Klasse wird später zum Erfassen von Benutzereingaben verwendet.
Autorenmenü definieren
In diesem Abschnitt wiederholen wir hauptsächlich das, was unter Nutzung behandelt wurde. Nach diesem Abschnitt beherrschen Sie den Umgang mit UiTableSpecifier, UiFormSpecifier, UiShowSpecifier und UiFilterSpecifier.
Wir erstellen:
-
eine Tabelle, die alle Autoren anzeigt,
-
eine Schaltfläche zum Erstellen neuer Autoren über ein Formular,
-
eine Schaltfläche zum Löschen von Autoren,
-
eine Schaltfläche zum Reaktivieren von Autoren,
-
einen Filter für Autoren.
Autorentabelle
Wir möchten die Autoren in einer Tabelle anzeigen. Dafür müssen wir einen UiTableSpecifier erstellen. Wechseln Sie zu app/library/services/myLibrary/MyLibraryUiService im Bereich Author Menu.
Pro-Modus: Implementieren Sie die Tabelle selbst [TODOS 2.1.1—2.1.6].
buildAuthorTable:MyLibraryAuthor author = new MyLibraryAuthor()
UiTableSpecifier authorTableSpecifier = new UiTableSpecifier()
authorTableSpecifier.ui {
header {
column {label author.firstName_}
label author.lastName_
if(!isSelect) {
label author.isActive_
label "Delete Author"
}
}
TaackFilter.FilterBuilder filter = taackFilterService.getBuilder(MyLibraryAuthor)
.setMaxNumberOfLine(10)
.setSortOrder(TaackFilter.Order.ASC, author.lastName_)
if(isSelect) {
filter.addFilter(buildIsActiveAuthorFilter(author))
}
iterate(
filter.build()) { MyLibraryAuthor authorIterator ->
rowColumn {
// TODO 2.10: Add rowAction to showAuthor with author's first name as label
if (isSelect) {
// TODO 3.5.6: Add SELECT action icon to select author with their id and string representation
}
}
rowField authorIterator.lastName_
if(!isSelect) {
rowField authorIterator.isActive_
rowColumn {
// TODO 2.7.1: Add DELETE action icon linked to deleteAuthor controller action
// TODO 2.7.2: Add ACTIVATE action icon linked to activateAuthor controller action
}
}
}
}
Falls Sie Schwierigkeiten haben, diesen Code zu verstehen, lesen Sie bitte unter Nutzung nach.
Beachten Sie, dass wir buildIsActiveAuthorFilter hinzugefügt haben, was noch nicht implementiert wurde. Implementieren wir es jetzt.
Hinweis: Der Name des Autors wird erst angezeigt, wenn TODO 2.10 erledigt ist.
Pro-Modus: Implementieren Sie den Filter selbst [TODO 2.2.1].
buildIsActiveAuthorFilter:UiFilterSpecifier buildIsActiveAuthorFilter(MyLibraryAuthor author) {
UiFilterSpecifier isActiveAuthorFilter = new UiFilterSpecifier()
isActiveAuthorFilter.ui MyLibraryAuthor, {
section "Filter", {
filterFieldExpressionBool "Is Active", new FilterExpression(true, Operator.EQ, author.isActive_) //(1)
}
}
}
-
Wir erstellen eine
FilterExpression, die einen Wert, einen Operator und einFieldInfoentgegennimmt.
Es stehen verschiedene Operatoren zur Verfügung:
-
IN: in einer Liste von Werten,
-
NI: nicht in einer Liste von Werten,
-
EQ: gleich einem anderen Wert,
-
NE: ungleich einem anderen Wert,
-
LT: kleiner als ein anderer Wert,
-
IL: ähnlich wie ein anderer Wert (is like),
-
GT: größer als ein anderer Wert,
-
IS_EMPTY: ist leer
Wir möchten außerdem einen Filter hinzufügen, der die Autoren nach lastName filtert. Implementieren wir diesen Filter.
Pro-Modus: Implementieren Sie den Filter selbst [TODO 2.2.2].
buildAuthorFilter:UiFilterSpecifier buildAuthorFilter() {
MyLibraryAuthor author = new MyLibraryAuthor()
UiFilterSpecifier authorFilterSpecifier = new UiFilterSpecifier()
authorFilterSpecifier.ui MyLibraryAuthor, {
section "Author Filter", {
filterField author.lastName_
}
}
}
Falls Sie Schwierigkeiten haben, diesen Code zu verstehen, lesen Sie bitte unter Nutzung nach.
Ihre Tabelle ist nun vollständig; wir müssen sie nur noch auf der Seite rendern. Um zuvor erstellte UiSpecifier zu rendern, müssen wir taackUiService verwenden. Wir tun dies in einer Methode namens listAuthor. Wechseln Sie zu app/library/controller/myLibrary/MyLibraryController im Bereich Author Menu.
Pro-Modus: Implementieren Sie listAuthor selbst [TODO 2.3].
listAuthor:def listAuthor() {
UiTableSpecifier tableAuthorSpecifier = myLibraryUiService.buildAuthorTable()
UiFilterSpecifier filterAuthorSpecifier = myLibraryUiService.buildAuthorFilter()
taackUiService.show(new UiBlockSpecifier().ui {
tableFilter filterAuthorSpecifier, tableAuthorSpecifier, {
menuIcon ActionIcon.CREATE, this.&createAuthor as MethodClosure
}
}, myLibraryUiService.buildMenu())
}
Hinweis: ActionIcon verfügt über mehrere Icons. Die wichtigsten, die wir verwenden werden, sind: CREATE, EDIT, SAVE, DELETE, SHOW, IMPORT, EXPORT.
Sie können nun den Server starten und zu Ihrer neuen Anwendung (myLibrary.app) navigieren. Die Tabelle sollte funktionsfähig sein, aber derzeit sehen Sie nur die Tabellenköpfe, da sich noch keine Autoren in Ihrer Datenbank befinden. Fahren wir also damit fort, ein Formular zu erstellen und Objekte in der Datenbank zu speichern. Wir müssen nun createAuthor implementieren, wofür ein UiFormSpecifier erstellt werden muss.
Kehren wir zurück zu MyLibraryUiService.
Autorenformular
Pro-Modus: Implementieren Sie buildAuthorForm selbst [TODO 2.4].
buildAuthorForm:UiFormSpecifier buildAuthorForm(MyLibraryAuthor author) {
author ?= new MyLibraryAuthor(params)
UiFormSpecifier createAuthorSpecifier = new UiFormSpecifier()
createAuthorSpecifier.ui author, {
section "Author details", {
field author.firstName_
field author.lastName_
field author.dateOfBirth_
field author.isActive_
}
formAction MyLibraryController.&saveAuthor as MC
}
}
Kehren wir zurück zu MyLibraryController. Wir werden dieses Formular in einem Modal-Dialog rendern.
Pro-Modus: Implementieren Sie createAuthor [TODO 2.5]
createAuthor:def createAuthor(MyLibraryAuthor author) {
UiFormSpecifier formAuthorSpecifier = myLibraryUiService.buildAuthorForm(author)
taackUiService.show(new UiBlockSpecifier().ui {
modal {
form formAuthorSpecifier
}
})
}
Jetzt müssen wir den Autor speichern. Implementieren wir saveAuthor.
Pro-Modus: Implementieren Sie saveAuthor [TODO 2.6].
@Transactional
def saveAuthor() {
taackSaveService.saveThenReloadOrRenderErrors(MyLibraryAuthor)
}
Wir haben nun eine voll funktionsfähige Tabelle, in der wir Autoren anzeigen und hinzufügen können. Starten Sie den Server erneut. Sie sollten nun auf die Schaltfläche klicken und das Formular ausfüllen können. Als Nächstes möchten wir Autoren löschen und reaktivieren können. Implementieren wir die Methoden deleteAuthor und reactivateAuthor. Navigieren wir zu MyLibraryUiService in buildAuthorTable.
Autor löschen und reaktivieren
Wechseln Sie zu myLibraryUiService in buildAuthorTable.
Pro-Modus: Fügen Sie die Schaltflächen hinzu [TODO 2.7].
rowAction ActionIcon.DELETE * IconStyle.SCALE_DOWN, MyLibraryController.&deleteAuthor as MC, authorIterator.id
rowAction ActionIcon.CREATE * IconStyle.SCALE_DOWN, MyLibraryController.&activateAuthor as MC, authorIterator.id
Navigieren Sie zurück zu MyLibraryController, um die Methoden deleteAuthor & activateAuthor zu implementieren.
Pro-Modus: Implementieren Sie die Methoden [TODO 2.8 & 2.9]
deleteAuthor:@Transactional
def deleteAuthor(MyLibraryAuthor author) {
author.isActive = false
redirect action: 'listAuthor'
}
activateAuthor:@Transactional
def activateAuthor(MyLibraryAuthor author) {
author.isActive = true
redirect action: 'listAuthor'
}
Wir möchten weitere Informationen über den Autor in einem Modal-Dialog anzeigen können.
Implementieren wir nun die Methode showAuthor. Zuerst müssen wir einen Link zu dieser Methode und einen UiShowSpecifier in myLibraryUiService erstellen.
Navigieren wir zu MyLibraryUiService in buildAuthorTable.
Pro-Modus: Fügen Sie die Schaltflächen hinzu [TODO 2.10].
Fügen Sie die Show-Aktion hinzu. Ersetzen Sie TODO 2.10:
rowAction authorIterator.firstName, MyLibraryController.&showAuthor as MC, authorIterator.id
Hinweis: Diesmal gibt es kein ActionIcon. Stattdessen wird ein Link zum authorName hinzugefügt, der zu showAuthor weiterleitet.
Pro-Modus: Implementieren Sie buildAuthorShow [TODO 2.11]
buildAuthorShow:UiShowSpecifier buildAuthorShow(MyLibraryAuthor author) {
UiShowSpecifier authorShowSpecifier = new UiShowSpecifier()
authorShowSpecifier.ui(author, {
fieldLabeled author.firstName_
fieldLabeled author.lastName_
fieldLabeled author.dateOfBirth_
fieldLabeled author.isActive_
})
}
Wir rendern buildAuthorShow in einem Modal-Dialog mithilfe von showAuthor.
Pro-Modus: Implementieren Sie showAuthor [TODO 2.12]
showAuthor:def showAuthor(MyLibraryAuthor author) {
UiTableSpecifier tableBookSpecifier = myLibraryUiService.buildBookTable(author)
UiFilterSpecifier filterBookSpecifier = myLibraryUiService.buildBookFilter()
UiShowSpecifier showAuthorSpecifier = myLibraryUiService.buildAuthorShow(author)
taackUiService.show(new UiBlockSpecifier().ui {
modal {
show showAuthorSpecifier
tableFilter filterBookSpecifier, tableBookSpecifier
}
})
}
Herzlichen Glückwunsch! Sie haben nun alles implementiert, was Sie zum Anzeigen, Hinzufügen, Löschen, Reaktivieren und Betrachten von Autoren benötigen. Starten Sie den Server erneut und testen Sie alle neuen Implementierungen.
Büchermenü definieren
Wir möchten nun Bücher in einer Tabelle anzeigen. Dafür müssen wir einen weiteren UiTableSpecifier erstellen. Wechseln Sie zu app/library/services/myLibrary/MyLibraryUiService im Bereich Book Menu.
Pro-Modus: Implementieren Sie die Tabelle selbst [TODOS 3.1.1 - 3.1.6].
buildBookTable:UiTableSpecifier buildBookTable(MyLibraryAuthor author = null) {
MyLibraryBook book = new MyLibraryBook()
UiTableSpecifier bookTableSpecifier = new UiTableSpecifier()
bookTableSpecifier.ui {
header {
column {label book.title_}
if (!author) {sortableFieldHeader book.author_}
column {
label "Number of instances "//book.numberOfInstances
}
if (!author) {
column {
label "Modify number of Book Instances"
}
}
}
TaackFilter.FilterBuilder filter = taackFilterService.getBuilder(MyLibraryBook)
.setMaxNumberOfLine(10)
.setSortOrder(TaackFilter.Order.ASC, book.title_)
if(author) {
filter.addRestrictedIds(author.listOfBooks*.id as Long[])
}
iterate(
filter.build()) { MyLibraryBook bookIterator ->
rowColumn {
// TODO 3.13: Add SHOW (showBook) action above title field in the rowColumn, this will be used to modify a book.
rowAction ActionIcon.EDIT * IconStyle.SCALE_DOWN, MyLibraryController.&createBook as MC, bookIterator.id
rowField bookIterator.title_
}
if (!author) {rowField bookIterator.author_}
rowColumn {
// TODO 3.8.1: Display number of instances (call getNumberOfInstances) and show as rowField.
}
if (!author) {
rowColumn {
// TODO 3.9: If author is null, add purchase and select actions for managing book instances.
}
}
}
}
}
Wir möchten einen Filter hinzufügen, um Bücher nach Titel zu filtern. Implementieren wir ihn jetzt.
Pro-Modus: Implementieren Sie den Filter selbst [TODO 3.2].
buildBookFilter:UiFilterSpecifier buildBookFilter() {
MyLibraryBook book = new MyLibraryBook()
UiFilterSpecifier bookFilterSpecifier = new UiFilterSpecifier()
bookFilterSpecifier.ui MyLibraryBook, {
section "Book Filter", {
filterField book.title_
}
}
}
Wir haben nun eine Tabelle und einen Filter; damit können wir eine Seite rendern, die beide enthält. Wechseln Sie zu app/library/controller/myLibrary/MyLibraryController im Bereich Book Menu.
Pro-Modus: Implementieren Sie listBook selbst [TODO 3.3].
listBook:def listBook() {
UiTableSpecifier tableBookSpecifier = myLibraryUiService.buildBookTable()
UiFilterSpecifier filterBookSpecifier = myLibraryUiService.buildBookFilter()
taackUiService.show(new UiBlockSpecifier().ui {
tableFilter filterBookSpecifier, tableBookSpecifier, {
menuIcon ActionIcon.CREATE, this.&createBook as MethodClosure
}
}, myLibraryUiService.buildMenu())
}
Sie können nun den Server starten. Die Büchertabelle sollte funktionsfähig sein, aber derzeit sehen Sie nur die Tabellenköpfe, da sich noch keine Bücher in Ihrer Datenbank befinden. Fahren wir also damit fort, ein Formular zu erstellen und Objekte in der Datenbank zu speichern. Wir müssen nun createBook implementieren, wofür ein UiFormSpecifier erstellt werden muss.
Kehren wir zurück zu MyLibraryUiService.
Pro-Modus: Implementieren Sie buildBookForm selbst [TODO 3.4].
buildBookForm:UiFormSpecifier buildBookForm(MyLibraryBook book) {
book ?= new MyLibraryBook(params)
UiFormSpecifier bookFormSpecifier = new UiFormSpecifier()
bookFormSpecifier.ui book, {
section "Book details", {
field book.title_
ajaxField book.author_, MyLibraryController.&selectAuthor as MC //(1)
field book.numberOfPages_
field book.description_
}
formAction MyLibraryController.&saveBook as MC
}
}
-
Hier verwenden wir ein
AjaxField, um die Informationen vonselectAuthorabzurufen.
Kehren wir zurück zu MyLibraryController und implementieren selectAuthor zur Verdeutlichung.
Pro-Modus: Implementieren Sie selectAuthor selbst im Bereich Author Menu [TODO 3.5]. Hinweis: 3.5.6 befindet sich in buildAuthorTable.
selectAuthor:def selectAuthor() {
UiTableSpecifier tableAuthorSpecifier = myLibraryUiService.buildAuthorTable(true) //(1)
UiFilterSpecifier filterAuthorSpecifier = myLibraryUiService.buildAuthorFilter()
taackUiService.show(new UiBlockSpecifier().ui {
modal {
tableFilter filterAuthorSpecifier, tableAuthorSpecifier
}
})
}
-
Beachten Sie, dass
buildAuthorTableeinenBoolean-Wert entgegennimmt, um dieisSelect-Version desUiTableSpecifieranzuzeigen.
rowAction tr('default.role.label'), ActionIcon.SELECT * IconStyle.SCALE_DOWN, authorIterator.id, authorIterator.toString()
Pro-Modus: Implementieren Sie createBook [TODO 3.6]
def createBook(MyLibraryBook book) {
UiFormSpecifier tableFormSpecifier = myLibraryUiService.buildBookForm(book)
taackUiService.show new UiBlockSpecifier().ui {
modal {
form tableFormSpecifier
}
}
}
Jetzt müssen wir das Buch speichern; implementieren wir saveBook.
Pro-Modus: Implementieren Sie saveBook [TODO 3.7].
@Transactional
def saveBook() {
taackSaveService.saveThenReloadOrRenderErrors(MyLibraryBook)
}
Sie haben nun eine voll funktionsfähige Tabelle, in der wir Bücher anzeigen und hinzufügen können. Implementieren wir als Nächstes purchaseBook und selectBookInstance, da wir bookInstances eines bestimmten Buches erwerben und löschen können möchten. Navigieren wir zu MyLibraryUiService in buildBookTable.
Pro-Modus: Implementieren Sie die Schaltflächen und zeigen Sie numberOfInstances an [TODOS 3.8].
numberOfInstances. Ersetzen Sie TODO 3.8.1rowField bookIterator.numberOfInstances_
rowAction ActionIcon.DELETE * IconStyle.SCALE_DOWN, MyLibraryController.&selectBookInstance as MC, bookIterator.id
rowAction ActionIcon.ADD * IconStyle.SCALE_DOWN, MyLibraryController.&purchaseBook as MC, bookIterator.id
Wir möchten, dass der Benutzer auswählt, wie viele BookInstances er erwerben möchte. Daher müssen wir einen UiFormSpecifier namens buildBookPurchase implementieren.
Pro-Modus: Implementieren Sie den UiFormSpecifier [TODO 3.9]
buildBookPurchase:UiFormSpecifier buildBookPurchase(MyLibraryBook book) {
NumberForInstances numberForInstances = new NumberForInstances()
book ?= new MyLibraryBook(params)
UiFormSpecifier bookPurchaseSpecifier = new UiFormSpecifier()
bookPurchaseSpecifier.ui book, {
section "Purchase Number", {
field numberForInstances.numberOfInstances_ //(1)
}
formAction MyLibraryController.&purchaseAndSaveBook as MC
}
}
-
Beachten Sie, dass wir eine Klasse verwenden, um die
numberOfInstancesabzurufen, die der Benutzer erwerben möchte. Diese Zahl dient nur zur Eingabe und wird im Gegensatz zu anderen Klasseninstanzen nicht in der Datenbank gespeichert.
Navigieren Sie zurück zu MyLibraryController, um die Methoden purchaseBook & selectBookInstance zu implementieren.
Pro-Modus: Implementieren Sie die Methoden [TODO 3.10–3.12]
purchaseBook:def purchaseBook(MyLibraryBook book) {
UiFormSpecifier tableAddBookInstanceSpecifier = myLibraryUiService.buildBookPurchase(book)
taackUiService.show new UiBlockSpecifier().ui {
modal {
form tableAddBookInstanceSpecifier
}
}
}
purchaseAndSaveBook:@Transactional
def purchaseAndSaveBook(NumberForInstances numberForInstances, MyLibraryBook book) {
for (int i = 0; i < (numberForInstances.numberOfInstances) as Integer; i++) {
MyLibraryBookInstance newBookInstance = new MyLibraryBookInstance()
newBookInstance.book = book
book.addToListOfBookInstance(newBookInstance)
}
taackUiService.ajaxReload()
}
selectBookInstance:def selectBookInstance(MyLibraryBook book) {
UiTableSpecifier bookInstanceTableSpecifier = myLibraryUiService.buildInstanceBookTable(book)
taackUiService.show new UiBlockSpecifier().ui {
modal true, {
table bookInstanceTableSpecifier
}
}
}
Implementieren wir nun die Methode showBook. Zuerst müssen wir einen UiShowSpecifier in myLibraryUiService erstellen.
Navigieren wir zu MyLibraryUiService in buildBookTable.
Pro-Modus: Fügen Sie die Schaltflächen hinzu [TODO 3.13].
Fügen Sie die Show-Aktion hinzu. Ersetzen Sie TODO 3.13:
rowAction ActionIcon.SHOW * IconStyle.SCALE_DOWN, MyLibraryController.&showBook as MC, bookIterator.id
Pro-Modus: Implementieren Sie buildBookShow [TODO 3.14]
buildBookShow: UiShowSpecifier buildBookShow(MyLibraryBook book) {
UiShowSpecifier bookShowSpecifier = new UiShowSpecifier()
bookShowSpecifier.ui(book, {
fieldLabeled book.title_
fieldLabeled book.author_
fieldLabeled book.numberOfPages_
fieldLabeled book.description_
fieldLabeled book.numberOfInstances_
})
}
Pro-Modus: Implementieren Sie showBook [TODO 3.15]
showBook:def showBook(MyLibraryBook book) {
UiShowSpecifier showBookSpecifier = myLibraryUiService.buildBookShow(book)
taackUiService.show(new UiBlockSpecifier().ui {
modal {
show showBookSpecifier
}
})
}
Wir implementieren nun deleteBookInstance. Wir möchten das spezifische Buchexemplar auswählen, das wir löschen möchten. Daher müssen wir eine buildBookInstanceTable mit einer isSelect-Option erstellen. Außerdem benötigen wir einen Filter buildIsActiveBookInstances, da es sich um ein logisches Löschen (Soft Delete) handelt (wir filtern inaktive BookInstances heraus).
Beginnen wir mit der Implementierung des Filters buildIsActiveBookInstances.
Pro-Modus: Implementieren Sie buildIsActiveBookInstances [TODO 3.16].
buildIsActiveBookInstances.UiFilterSpecifier buildIsActiveBookInstances(MyLibraryBook book) {
MyLibraryBookInstance bookInstance = new MyLibraryBookInstance()
UiFilterSpecifier bookInstanceFilterSpecifier = new UiFilterSpecifier()
bookInstanceFilterSpecifier.sec MyLibraryBookInstance, {
filterFieldExpressionBool new FilterExpression(true, Operator.EQ, bookInstance.isActive_)
}
}
Nun können wir buildBookInstanceTable implementieren.
Pro-Modus: Implementieren Sie buildBookInstanceTable [TODO 3.17].
buildBookInstanceTable.UiTableSpecifier buildInstanceBookTable(
MyLibraryBook book,
MyLibraryBookInstance bookInstance = null) {
UiTableSpecifier table = new UiTableSpecifier()
table.ui {
header {
label "Serial Number"
column {label "Delete"}
}
TaackFilter.FilterBuilder filter = taackFilterService
.getBuilder(MyLibraryBookInstance)
.addRestrictedIds(book.listOfBookInstance*.id as Long[])
filter.addFilter(buildIsActiveBookInstances(book))
iterate(filter.build()) { MyLibraryBookInstance bookInstanceIterator ->
rowField bookInstanceIterator.serialNumber_
rowColumn {
rowAction ActionIcon.DELETE * IconStyle.SCALE_DOWN,
MyLibraryController.&deleteBookInstances as MC,
bookInstanceIterator.id, [bookId:book.id]
}
}
}
}
Implementieren wir nun deleteBookInstances.
Pro-Modus: Implementieren Sie deleteBookInstances [TODO 3.18].
deleteBookInstances:@Transactional
def deleteBookInstances(MyLibraryBookInstance bookInstance) {
MyLibraryBook book = MyLibraryBook.get(params.long('bookId'))
UiTableSpecifier bookInstanceTable = myLibraryUiService.buildInstanceBookTable(book)
bookInstance.isActive = false
bookInstance.save(flush: true, validate: false)
taackUiService.show new UiBlockSpecifier().ui {
closeModalAndUpdateBlock { //(1)
tableFilter(
myLibraryUiService.buildBookFilter(), //(2)
myLibraryUiService.buildBookTable(), //(2)
) {
menuIcon ActionIcon.CREATE, this.&createBook as MethodClosure //(2)
}
modal {
table bookInstanceTable //(3)
}
}
}
}
-
Die Verwendung von
closeModalAndUpdateBlockermöglicht es dem Benutzer, den aktualisierten Status der gelöschtenBookInstancesofort zu sehen. Es schließt den Modal-Dialog unmittelbar nachdem der Benutzer eineBookInstanceausgewählt hat. -
Wir rufen die Builder auf, die zum Anzeigen der Bücher verwendet werden, damit
numberOfInstancesin der Büchertabelle aktualisiert wird, wenn wir den Modal-Dialog schließen. -
Wir öffnen erneut einen Modal-Dialog. Wenn der Benutzer eine
BookInstanceauswählt, wird der Modal-Dialog geschlossen und anschließend wieder geöffnet, sodass die ausgewählteBookInstancenicht mehr angezeigt wird.
Herzlichen Glückwunsch! Sie haben den ersten Teil dieses Projekts abgeschlossen.