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.

build.gradle
 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.

  1. A module for the domain ../client/src/app/bar/bar.module.ts.

  2. A routing module ../client/src/app/bar/bar-routing.module.ts.

  3. A javascript representation of the domain class ../client/src/app/bar/bar.ts.

  4. A service to handle the CRUD of the domain ../client/src/app/bar/bar.service.ts.

  5. Components for list, persist, and show ../client/src/app/bar/bar-show.component.ts.

  6. 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.

  1. A module will be created for the association.

  2. A service will be created to retrieve the list of the associated domain.

  3. A javascript representation of the associated domain class will be created.

  4. 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.

application.yml
 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

grails.codegen.angular.baseDir

The base directory where assets should be stored

../client/src/app

grails.codegen.angular.bootstrapModule

The path to the bootstrap module relative to the base directory

app.module.ts

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:

  1. The propertyMarkupRenderer bean has been set to an instance of AngularPropertyMarkupRenderer that only overrides the getStandardAttributes method to add an [(ngModel)] attribute.

  2. The contextMarkupRenderer has been set to an instance of AngularContextMarkupRenderer that overrides the list output context to use an *ngFor.

  3. 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.