Git Product home page Git Product logo

grails-angular-scaffolding's Introduction

This is a Grails plugin that allows you to use Angular.js based scaffolding.

Usage

After installing the plugin run:

grails ng-install-templates

This will install the Angular JS scaffolding templates into your project under src/templates/scaffolding. It will also copy some common HTML template files that will be shared by all scaffolded views into web-app/ng-templates.

Static scaffolding

To generate the controller and views for a domain class run:

grails ng-generate-all _domain class name_

Dynamic scaffolding

Dynamic scaffolding is only supported for the controller. Currently you will need to generate the views for each domain class.

To generate only the views and use a dynamically scaffolded controller run:

grails ng-generate-views _domain class name_

How it works

Instead of the Grails controller rendering a view for each page using a GSP the controller's index action serves up an initial framework page containing the JavaScript resources required by Angular JS. The remaining controller actions simply return JSON data.

Each 'page' in the CRUD interface for a particular domain class is accessed using a URL fragment; #/list, #/create, etc. The page content is rendered by Angular JS using an HTML template and the data to populate the page is retrieved from the controller using an AJAX call.

The HTML templates need to be generated individually for each domain class as they contain the markup needed to represent the properties of that class in a list or a form. However, the JavaScript used for the CRUD interface is the same for all domain classes.

Customizing

Enable optimistic locking check

By default, the JSON converter does not send the object's "version" field generated by Hibernate. Because of that, the controller does not check when concurrent modifications occur. To enable optimistic locking check, simply add the following in your Config.groovy:

grails.converters.json.domain.include.version = true

Using Grails RESTful URL mappings

By default Grails uses a non-RESTful URL scheme where the controller action representing the verb is part of the URL. In the Grails documentation there is a section on configuring RESTful URL mappings. If you want to use such a URL scheme with this plugin you will need to override the web-app/js/grails-default.js file that configures an Angular $resource service that maps to your Grails controllers.

Limitations

This is an experimental work-in-progress. See the issues list for outstanding features.

Demo

There is a demo of this plugin running on Cloud Foundry.

The demo application is also included under test/apps/grails-ng in this project.

Tests

There are some end-to-end tests that use Casper JS. To run the tests:

cd test/apps/grails-ng
grails run-app

Then in another terminal:

casperjs test --includes=test/casper/includes/casper-angular.coffee test/casper/specs/

grails-angular-scaffolding's People

Contributors

graemerocher avatar philixxx avatar robbugh avatar robfletcher avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

grails-angular-scaffolding's Issues

Bind Grails server side validation to Angular's errors model

See: [http://docs.angularjs.org/api/ng.directive:form]

Angular uses a different structure on the form controller field.$error.type, e.g. title.$error.required

It would be nice to bind errors from server side validation to this structure so the display could work the same way for both.

Validate input values

Add a validate action to the scaffolded controller that is triggered on blur of each input.

Twitter bootstrap

It appears that the angularjs-scaffolding (this plugin) has support for twitter bootstrap built into it already but it seems to have not been turned off for some reason (could be just a small oversight)

I turned on the bootstrap by easily adding the following line to the head section of this file locally: /src/templates/scaffolding/index.gsp

        <link rel="stylesheet" href="\${resource(dir: 'css', file: 'mobile.css')}" type="text/css">        

        <r:require module="angular-scaffolding"/>  
        <r:require modules="bootstrap"/>  <--------Added this
    </head>

Was this left out intentionally?

Pre-render based on URL

e.g. if the user goes directly to /show/1 then the initial page state should be rendered without the need to make another HTTP request to render the angular view.

Display errors

When save or update fails each field should be annotated with an error message and set to invalid.

Generate HTML templates

Ideally the generate-all and generate-views commands should do this although given the way they hardcode the files they deal with it might not be possible. In that case another script will be used.

Documentation

Document:

  • REST interface
  • directives
  • overriding templates

Is this project alive?

Hi rob,
I'm working on a new project with AngularJS and, as a Grails developer I decided to use your plugin.
The plugin project seems abandoned so I decided to work a little bit on it in my fork and I would like to contribute back some modifications:

  • upgraded version of AngularJS to 1.2.23
  • eliminated jQuery dependency
  • renamed directives with gas- prefix
  • some bug fixes
  • some new bugs...

Here is the fork: https://github.com/aberbenni/grails-angular-scaffolding
If you think to keep this plugin project alive and you think the work done is useful, please tell me and I will submit a pull request.

Anyone who wants to test the this new code is welcome. Keep in mind that the test app was not upgraded, so for a correct test just scaffold your domain.

ng-include

what path would I use for an ng-include
For example in
app/assets/templates/posts is the index.html.erb
On that page I would like ng-include a sidebar that will be shared with other Post templates.
I tried

and many others.
Thanks!
Al

unable to run the demo app

Please what's the easiest way to run the app in test/apps/grails-ng ?
Trying grails run-app from the grails-ng directory, but no success.
thanks

'required' is set on all fields

Within the generated create.html and update.html files, the 'required' is set for all of the fields regardless whether they are nullable/blankable on the domain class.

I see that in the scafollding's renderFieldForProperty method there is a 'required' boolean defined and it seems to do be doing the right thing. It's just not used when input field is being written out:

<input type="text" id="${prefix}${p.name}" name="${prefix}${p.name}"  required  data-ng-model="item.${prefix}${p.name}">

I fixed it for myself by:

<input type="text" id="${prefix}${p.name}" name="${prefix}${p.name}" <% if(required) print " required " %> data-ng-model="item.${prefix}${p.name}">

ng-generate-all and ng-generate-all fail when generating for create.

ng-generate-* generate the htmls for list and show and throw a NullPointerException when proccessing create.

This is the exception that is thrown

java.lang.NullPointerException: Cannot get property 'matches' on null object
    at SimpleTemplateScript12.renderStringEditor(SimpleTemplateScript12.groovy:64)
    at SimpleTemplateScript12.this$4$renderStringEditor(SimpleTemplateScript12.groovy)
    at SimpleTemplateScript12$this$4$renderStringEditor.callCurrent(Unknown Source)
    at SimpleTemplateScript12.run(SimpleTemplateScript12.groovy:19)
    at grails.plugin.angularscaffolding.AngularTemplateGenerator$_closure1.doCall(AngularTemplateGenerator.groovy:41)
    at SimpleTemplateScript11.renderFieldForProperty(SimpleTemplateScript11.groovy:50)
    at SimpleTemplateScript11.renderFieldForProperty(SimpleTemplateScript11.groovy)
    at SimpleTemplateScript11.this$4$renderFieldForProperty(SimpleTemplateScript11.groovy)
    at SimpleTemplateScript11$this$4$renderFieldForProperty.callCurrent(Unknown Source)
    at SimpleTemplateScript11.run(SimpleTemplateScript11.groovy:32)
    at grails.plugin.angularscaffolding.AngularTemplateGenerator.generateView(AngularTemplateGenerator.groovy:75)
    at grails.plugin.angularscaffolding.AngularTemplateGenerator$_generateView_closure3.doCall(AngularTemplateGenerator.groovy:88)
    at grails.plugin.angularscaffolding.AngularTemplateGenerator.generateView(AngularTemplateGenerator.groovy:87)
    at grails.plugin.angularscaffolding.AngularTemplateGenerator.generateViews(AngularTemplateGenerator.groovy:50)
    at _NgGenerate_groovy.generateForDomainClass(_NgGenerate_groovy:43)
    at org.codehaus.gant.GantMetaClass.invokeMethod(GantMetaClass.java:133)
    at _NgGenerate_groovy$_run_closure1.doCall(_NgGenerate_groovy:25)
    at org.codehaus.gant.GantMetaClass.invokeMethod(GantMetaClass.java:133)
    at org.codehaus.gant.GantBinding$_initializeGantBinding_closure5_closure16_closure18.doCall(GantBinding.groovy:185)
    at org.codehaus.gant.GantBinding$_initializeGantBinding_closure5_closure16_closure18.doCall(GantBinding.groovy)
    at org.codehaus.gant.GantBinding.withTargetEvent(GantBinding.groovy:90)
    at org.codehaus.gant.GantBinding.this$4$withTargetEvent(GantBinding.groovy)
    at org.codehaus.gant.GantBinding$_initializeGantBinding_closure5_closure16.doCall(GantBinding.groovy:185)
    at org.codehaus.gant.GantBinding$_initializeGantBinding_closure5_closure16.doCall(GantBinding.groovy)
    at org.codehaus.gant.GantMetaClass.invokeMethod(GantMetaClass.java:133)
    at NgGenerateViews$_run_closure1.doCall(NgGenerateViews:10)
    at org.codehaus.gant.GantMetaClass.invokeMethod(GantMetaClass.java:133)
    at org.codehaus.gant.GantBinding$_initializeGantBinding_closure5_closure16_closure18.doCall(GantBinding.groovy:185)
    at org.codehaus.gant.GantBinding$_initializeGantBinding_closure5_closure16_closure18.doCall(GantBinding.groovy)
    at org.codehaus.gant.GantBinding.withTargetEvent(GantBinding.groovy:90)
    at org.codehaus.gant.GantBinding.this$4$withTargetEvent(GantBinding.groovy)
    at org.codehaus.gant.GantBinding$_initializeGantBinding_closure5_closure16.doCall(GantBinding.groovy:185)
    at org.codehaus.gant.GantBinding$_initializeGantBinding_closure5_closure16.doCall(GantBinding.groovy)
    at gant.Gant$_dispatch_closure5.doCall(Gant.groovy:381)
    at gant.Gant$_dispatch_closure7.doCall(Gant.groovy:415)
    at gant.Gant$_dispatch_closure7.doCall(Gant.groovy)
    at gant.Gant.withBuildListeners(Gant.groovy:427)
    at gant.Gant.this$2$withBuildListeners(Gant.groovy)
    at gant.Gant$this$2$withBuildListeners$0.callCurrent(Unknown Source)
    at gant.Gant$this$2$withBuildListeners$0.callCurrent(Unknown Source)
    at gant.Gant.dispatch(Gant.groovy:415)
    at gant.Gant.this$2$dispatch(Gant.groovy)
    at gant.Gant.invokeMethod(Gant.groovy)
    at gant.Gant.executeTargets(Gant.groovy:591)
    at gant.Gant.executeTargets(Gant.groovy:590)

I did some digging and i reached at a conclusion, that this is occurring on line 64 of renderEditor file

 private String renderStringEditor(domainClass, property, name) {
        def sb = new StringBuilder()
        sb << '<input type="text"'
        sb << ' id="' << name << '"'
        sb << ' name="' << name << '"'
        sb << ' data-ng-model="item.' << name << '"'
        if (cp.matches) sb << ' pattern="' << cp.matches << '"'
        if (isRequired()) sb << ' required'
        sb << '>'
        sb as String
    }
//I could't find where cp was declared

missing resources when generating static scaffolding

Hello Robert

Tried to use static scaffolding without success/

  • get grails-angular-scaffolding from git hub
  • create a new grals project
    *update buildConfig.groovy adding
    grails.plugin.location."angular-scaffolding" = "/home/corinne/work/workspace/grails-angular-scaffolding"
  • create a domain class
  • use ng-install-templates
  • use ng-generate-all pkge.domainClass (* not supported)
  • launch the app

When accessing URL http://localhost:8080/toto2/person/index#/list, bumped into JS errors:

Error: Failed to load template: /ng-templates/alert.html
("",404,(function (name) {"use strict";if (!headersObj) {headersObj = parseHeaders(headers);}if (name) {return headersObj[lowercase(name)] || null;}return headersObj;}),[object Object])@http://localhost:8080/toto2/static/plugins/angular-scaffolding-1.0-SNAPSHOT/js/angular/angular-1.0.0.js:4363
([object Object])@http://localhost:8080/toto2/static/plugins/angular-scaffolding-1.0-SNAPSHOT/js/angular/angular-1.0.0.js:8631
([object Object])@http://localhost:8080/toto2/static/plugins/angular-scaffolding-1.0-SNAPSHOT/js/angular/angular-1.0.0.js:6594
([object Object],(void 0))@http://localhost:8080/toto2/static/plugins/angular-scaffolding-1.0-SNAPSHOT/js/angular/angular-1.0.0.js:6670
((function () {"use strict";result.resolve((errback || defaultErrback)(reason));}))@http://localhost:8080/toto2/static/plugins/angular-scaffolding-1.0-SNAPSHOT/js/angular/angular-1.0.0.js:7769
()@http://localhost:8080/toto2/static/plugins/angular-scaffolding-1.0-SNAPSHOT/js/angular/angular-1.0.0.js:7641
()@http://localhost:8080/toto2/static/plugins/angular-scaffolding-1.0-SNAPSHOT/js/angular/angular-1.0.0.js:7855
done(404,"","Server: Apache-Coyote/1.1\nContent-Length: 0\nDate: Sun, 01 Jul 2012 17:24:27 GMT\n")@http://localhost:8080/toto2/static/plugins/angular-scaffolding-1.0-SNAPSHOT/js/angular/angular-1.0.0.js:8844
completeRequest(done,404,"","Server: Apache-Coyote/1.1\nContent-Length: 0\nDate: Sun, 01 Jul 2012 17:24:27 GMT\n")@http://localhost:8080/toto2/static/plugins/angular-scaffolding-1.0-SNAPSHOT/js/angular/angular-1.0.0.js:8984
([object Event])@http://localhost:8080/toto2/static/plugins/angular-scaffolding-1.0-SNAPSHOT/js/angular/angular-1.0.0.js:8955

http://localhost:8080/toto2/static/plugins/angular-scaffolding-1.0-SNAPSHOT/js/angular/angular-1.0.0.js
Line 5525

ng-generate-all error.

ng-generate-all angular.test.sector
| Error Error running script ng-generate-all sector: startup failed:
_NgGenerate_groovy: 115: The return type of java.lang.Object getTemplateNames() in AngularTemplateGenerator is incompatible with java.util.Set getTemplateNames() in org.codehaus.groovy.grails.scaffolding.AbstractGrailsTemplateGenerator
. At [115:2] @ line 115, column 2.
1 error

Demo app is caching JSON responses

It's very difficult to see stuff working as data is getting cached so you need to hard refresh to see changes. This doesn't seem to be a problem when running locally so I think it's cloud foundry doing it.

no module: grailsService

I've getting a javascript error on a pretty simple example and I'm wondering what I misconfigured.

  • grails create-app grails-angular
  • cd grails-angular
  • cp -r /grails-angular-scaffolding lib/angular-scaffolding-1.0-SNAPSHOT
  • add
    • grails.plugin.location.'angular-scaffolding'='lib/angular-scaffolding-1.0-SNAPSHOT'
    • to BuildConfig
  • grails add-domain grails.angular.Book
  • grails ng-install-templates
  • grails ng-generate-all grails.angular.Book
  • grails run-app

gives me

Error: No module: grailsService
http://localhost:8080/static/plugins/angular-scaffolding-1.0-SNAPSHOT/js/angular/angular-1.0.6.js
Line 1104

Any Suggestions?

Plugin not working with Grails 2.3

Probably because plugin support evolved in the last release, I have the following error whan running scaffolding:

| Error Error running script ng-generate-all com.tb.app.Requestmap --stacktrace: startup failed:
_NgGenerate_groovy: 60: unable to resolve class DefaultGrailsTemplateGenerator
@ line 60, column 1.
1 error
(NOTE: Stack trace has been filtered. Use --verbose to see entire trace.)
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
_NgGenerate_groovy: 60: unable to resolve class DefaultGrailsTemplateGenerator
@ line 60, column 1.
1 error

    at gant.Gant.compileScript(Gant.groovy:631)
    at gant.Gant.this$2$compileScript(Gant.groovy)
    at org.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1259)
    at gant.Gant$_closure1.doCall(Gant.groovy:129)
    at org.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1259)
    at org.codehaus.gant.IncludeTargets.leftShift(IncludeTargets.groovy:57)
    at org.codehaus.gant.IncludeTargets$leftShift.call(Unknown Source)
    at NgGenerateAll.run(NgGenerateAll:1)
    at NgGenerateAll$run.call(Unknown Source)
    at gant.Gant.prepareTargets(Gant.groovy:607)
    at org.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1259)
    at org.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1259)

Filter list

Filter the list data (without truncating the length of the page).

Rich UI

Rather than re-rendering the whole page for create, edit and show views they could be displayed in a lightbox.

show.html (fix attached)

Currently inside the show.html scaffolding template the following code has an issue when you have null values returned -- values end up being displayed against wrong labels...

Example:

  • in the following example this record is not approved yet -- so no value -- however the show page will display the lastupdate value beside the approved date field.

Create Date: created date ends up (correct) spot
Approved Date: last update date ends up here (incorrect)
Last Updated: left blank (incorrect)

Changed the following code to output a table and the data came out correct:

https://gist.github.com/dmarley/6307091

Templates as script blocks

Rather than creating more HTTP requests it might be preferable to have script blocks in the page. To avoid duplication the common templates could be placed in the ng-app.gsp layout and the controller specific ones in the index.gsp.

show loading icon

It'd be great to show loading icon instead of the table header...cuz it changes its size.

Cheers,
Raúl Gomis

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.