Last updated by bronoman 3 years ago
This idea has been implemented as the ScaffoldTags Plugin

Abstract

Scaffolding is great. It lets you edit how all of your domain beans are displayed for various pages.But the built-in scaffolding in 0.4.x only lets you have limited control. It would be nice to control not just the general page layout, but the actual editors displayed, and how fields are displayed. It would also nice to be able to override that behavior for specific subclasses, beans, or even specific fields on specific beans, or for specific relationships.

The basic idea

This assumes that scaffolding is in use. In general, the following rules would apply:

  • There are templates for each specific type of action (editor, view, list, and possibly others). The choice of which type of action is to be used, and which properties are to be filtered out is determined by the view templates (i.e. edit.gsp, create.gsp).
  • The handling of all fields in a domain is handled by a special template that handles how a domain is displayed for the given action template type.
  • Each field class type is edited via a gsp page that provides the template for that specific type, as well as its subclasses.
For instance, you would have an editor that edits java.util.Date that can also handle java.sql.Date. Subclasses could be overridden if desired; for instance a java.sql.Time could be edited differently from Date even though they share the same base class.
  • Similarly, each relationship type is edited via a gsp that provides a template for that type of relationship. There would be separate templates for 1-to-1/n-to-1 and 1-to-n/m-to-n relationships. I'm not sure if we'd want to break that up as well to permit having separate 1-to-1 and n-to-1 implementations; I'd rather hold off on that for now until I have a good sense on when it'd be useful.
  • Primitives are mapped to their container class (i.e. int to java.lang.Integer, char to java.lang.Character, etc.) so as to avoid the need for duplicate implementations.
The web developer may want to override the default implementation. For that, the following would apply:
  • It may be desirable to change these implementations in a given application. To do that, the developer would install these scaffolding templates in his application and edit them there (under src/templates/scaffolding), as one normally would do today.
  • It may also be desirable to change these implementations for a given domain class in a given application. This would be possible by having a domain-specific implementation folder. For instance, you may want the selector for a Date to be a Javascript-based calendar widget for some domains, or a text-based time selector for others.
  • It may also be desirable to change the implementations for a relationship with a given domain class.
For instance, you may want all selections of User instances to use a different selector (perhaps one with photos) from that used to select Product instances (which may involve a Javascript-based popup). For another example, you may want all displays of users in friend networks to be photos, but not when displaying who wrote a comment.
  • It may further be desirable to change these implementation for a given field in a given domain class in the application.
This would be made possible by having a field-specific implementation. For instance, you may want a spinner widget for some integer fields in a domain class, or a slider for others.

More details

To extend the existing implementation of scaffolding, the following would be added to src/templates/scaffolding/editor in a given application (or for the root implementation, it would be GRAILS_HOME/src/grails/templates/scaffolding/editors).

  • domain.gsp - handles the display of all the domain field editors
  • type.java.lang.Boolean.gsp - handles boolean and java.lang.Boolean
  • type.java.lang.Number.gsp - handles byte, short, int, long, float, double, java.lang.Byte, java.lang.Short, java.lang.Integer, java.lang.Long, java.lang.Float, java.lang.Double
  • type.java.lang.String.gsp - handles java.lang.String
  • type.java.net.URL - handles java.net.URL
  • type.java.util.Calendar.gsp - handles java.util.Calendar
  • type.java.util.Currency.gsp - handles java.util.Currency
  • type.java.util.Date.gsp - handles java.util.Date, java.sql.Date, and java.sql.Time
  • type.java.util.Locale.gsp - handles java.util.Locale
  • type.java.util.TimeZone.gsp - handles java.util.Locale
  • array.java.lang.Byte.gsp - handles byte[] for file uploads
  • relation.one.gsp - handles n-to-1 and 1-to-1 relationships
  • relation.many.gsp - handles 1-to-n and m-to-n relationships
Here's how you would perform changes:
  • To change how a Date (and any subclass of Date) is edited in all cases, you would modify the editor template in type.java.util.Date.gsp.
  • To change how a java.sql.Time is edited but not java.util.Date, you would simply add a type.java.sql.Time.gsp.
  • To change how doubles are edited, you would add type.java.lang.Double.gsp
  • To change how a relationship is edited, you would edit relation.one.gsp (n-to-1, 1-to-1) or relation.many.gsp (1-to-n, n-to-n).
  • To change the implementation of java.lang.Date for a specific Domain class (for instance, let's assume you have an Event domain class), you would add an editor template in the domain class's subdirectory, as bean.event/type.java.lang.Date.gsp.
  • If you had two "favoriteBooks" and "otherBooks" 1-to-n relationships between User and Book, to change the implementation of the selectors for favoriteBooks but not for otherBooks, you would add an editor bean.user/favoriteBooks.gsp. To change it for all 1-to-n relationships with books in the user bean, you would add an editor bean.user/many.book.gsp. To change it for all 1-to-n relationships with books in +all+ beans, you would add an editor many.book.gsp at the root level.

Implementation

The current non-plugin implementation can be downloaded here: ^src.zip (+)

This should be installed under the root directory of an application which is using (or for which you'd like to use) scaffolding. I don't have a plugin version of this yet. Once I figure that out I'll modify the link above.

Other ideas


Some other ideas I had (added as I come up with them):

  • Maybe we'd also like to let users control the display of a specific domain without forcing them to lose all scaffolding support.
It might be nice to scaffold what is used to display the fields but control the actual layout.