1. Introduction
The goal of this plugin is to provide basic CRUD abilities using Angular in a single page application. It is designed to be used alongside the angular profile, however it can be used in applications that were not created from the angular profile. This guide will cover what functionality you can expect from this plugin, as well as how you can change that functionality to meet your needs.
2. Installation
To start using this plugin, add it to your build.gradle
like the example below. If you created your project with the angular profile in Grails 3.2.0 or higher, this is done automatically.
buildscript {
...
dependencies {
classpath "org.grails.plugins:angular-scaffolding:2.0.0"
}
}
dependencies {
...
compile "org.grails.plugins:angular-scaffolding:2.0.0"
}
3. Usage
To use this plugin, execute the ngGenerateAll
command and pass the fully qualified path of a domain class.
$ grails ngGenerateAll com.foo.Bar //or just Bar
You can also execute the command via Gradle.
$ ./gradlew ngGenerateAll -Pargs="com.foo.Bar"
The default root path where assets will be created is "../client/src/app". That is because the plugin is configured by default to work with the angular profile which creates a multi-project build. To change that setting and others, see the configuration section.
The command will generate everything required to create, read, update, and delete instances of domain classes with Angular. The following will be created if they don’t already exist.
-
A module for the domain
../client/src/app/bar/bar.module.ts
. -
A routing module
../client/src/app/bar/bar-routing.module.ts
. -
A javascript representation of the domain class
../client/src/app/bar/bar.ts
. -
A service to handle the CRUD of the domain
../client/src/app/bar/bar.service.ts
. -
Components for list, persist, and show
../client/src/app/bar/bar-show.component.ts
. -
Templates for the components.
Based on the properties of your domain, some other assets may be generated.
3.1. File Properties
If your domain contains a byte[]
, Byte[]
, or java.sql.Blob
, the generated service will be modified to send a FormData
instead of a standard JSON request body.
3.2. Associations
If your domain has associations to other domain classes, that will influence the scaffolding.
-
A module will be created for the association.
-
A service will be created to retrieve the list of the associated domain.
-
A javascript representation of the associated domain class will be created.
-
The associated module will be imported into the module of the domain class being rendered.
When generating assets for a domain class that already has a module created via an association, ensure you inform the command to overwrite. |
$ grails ngGenerateAll com.foo.Bar true
3.3. Bootstrap Module
If a file with the name "app.module.ts" exists in the base directory, the scaffolding will attempt to import the newly created module into it.
If that process is successful, you will see a message like "Added Bar as a dependency to your bootstrap module".
If it is not successful, you will be responsible for importing it.
3.4. Assumptions
This plugin assumes you have an environment that supports ES6 modules and typescript. It is based upon the angular profile which uses the Angular CLI.
3.5. REST API
The scaffolding generated by this plugin includes a service to interact with a REST resource for the given domain object.
The generated service assumes that the server offers an API using a standard REST pattern, as per the following example for a domain object mapped to the /book
URL:
Action | HTTP Method | URL |
---|---|---|
List |
GET |
/book |
Create |
POST |
/book |
Show |
GET |
/book/5 |
Update |
PUT |
/book/5 |
Delete |
DELETE |
/book/5 |
3.5.1. Dates
In order for the scaffolding to work as designed, the databinding needs an additional date format to correctly parse date values sent by the client. The necessary format has been added by default in Grails 3.2.0.
Here is an example on how to configure the format.
grails:
databinding:
dateFormats:
- "yyyy-MM-dd'T'HH:mm:ss.SSSX"
3.6. Routing
If you are using the angular profile, the default index page is modified so that clicking on the link to the controller will automatically route you to the module the controller represents. If you are using this plugin in an existing application, you will have a little bit of work to do to use the generated assets.
The first step is to ensure the module is included in the page. If the bootstrap module is found, a dependency will automatically be created, however if the bootstrap module is not found, it is up to you to ensure the newly created module is imported.
The following routes are defined in the generated routing modules:
{path: 'domain', redirectTo: 'domain/list', pathMatch: 'full'},
{path: 'domain/list', component: DomainListComponent},
{path: 'domain/create', component: DomainPersistComponent},
{path: 'domain/edit/:id', component: DomainPersistComponent},
{path: 'domain/show/:id', component: DomainShowComponent}
Assuming the modules has been loaded on the index page and there is a <router-outlet></router-outlet>
directive on the index page, the URL would be http://localhost:8080/#/domain
. See the documentation for the Angular Router for more information.
4. Configuration
This plugin exposes configuration options to control how assets are rendered:
4.1. Asset Paths
Config Key | Description | Default Value |
---|---|---|
|
The base directory where assets should be stored |
|
|
The path to the bootstrap module relative to the base directory |
|
5. Customization
This plugin is an extension of Grails Scaffolding Core. To change how markup is rendered in the html templates, see the scaffolding core documentation. The following changes have been made:
-
The
propertyMarkupRenderer
bean has been set to an instance of AngularPropertyMarkupRenderer that only overrides the getStandardAttributes method to add an[(ngModel)]
attribute. -
The
contextMarkupRenderer
has been set to an instance of AngularContextMarkupRenderer that overrides the list output context to use an*ngFor
. -
Additional input and output renderers are registered with a priority of 0. If you wish your own renderers to be used, set a priority higher than 0. See the section on how properties are rendered in the scaffolding core documentation for more details on how to do so.
The JavaScript templates used to create assets can be overridden by executing grails ngInstallTemplates
. That will put a set of files in src/main/templates/angular
. You can modify the templates and they will be used in future angular code generation. You can safely remove any templates that you do not wish to override.