@PropertyLayout
Collects together all layout hints for a property of a domain object.
API
@interface PropertyLayout {
String cssClass() default ""; (1)
String describedAs() default ""; (2)
String fieldSetId() default "__infer"; (3)
String fieldSetName() default "__infer"; (4)
Where hidden() default Where.NOT_SPECIFIED; (5)
LabelPosition labelPosition() default LabelPosition.NOT_SPECIFIED; (6)
int multiLine() default -1; (7)
String named() default ""; (8)
Navigable navigable() default Navigable.NOT_SPECIFIED; (9)
PromptStyle promptStyle() default PromptStyle.NOT_SPECIFIED; (10)
Repainting repainting() default Repainting.NOT_SPECIFIED; (11)
String sequence() default ""; (12)
int typicalLength() default -1; (13)
}
1 | cssClass
Indicates the css class that a property should have, to allow more targeted styling in |
2 | describedAs
Description of this property, eg to be rendered in a tooltip. |
3 | fieldSetId
Specifies the id of associated FieldSet .XML layout is presentXML layout is absent |
4 | fieldSetName
Specifies the friendly-name of associated FieldSet . |
5 | hidden
Indicates where in the UI the property should not be visible. |
6 | labelPosition
In forms, positioning of the label (left, top or none) relative to the property value. |
7 | multiLine
For string properties (and parameters), render as a text area over specified number of lines. |
8 | named
Name of this property (overriding the name derived from its name in code). |
9 | navigable
Whether this property should be used to construct the navigable chain of breadcrumbs in the UI. |
10 | promptStyle
How the properties of this domain object are be edited, either PromptStyle#DIALOG dialog or PromptStyle#INLINE inline . |
11 | repainting
Indicates that the value held by the property never changes over time, even when other properties of the object do change. |
12 | sequence
The order of this member relative to other members in the same (layout) group, given in Dewey-decimal notation. |
13 | typicalLength
The typical entry length of a field, use to determine the optimum width for display. |
Members
cssClass
Indicates the css class that a property should have, to allow more targeted styling in application.css
.
fieldSetId
Specifies the id of associated FieldSet .XML layout is presentXML layout is absent
A FieldSet is a layout component for property grouping, that can either be specified via a Xxx.layout.xml
file (with Xxx
the domain object name) or is inferred by the framework via annotations (aka the programming model). FieldSet s are represented in-memory and requires a framework internal unique id per domain object type.
Following 2 scenarios have slightly different behavior:
When a XML layout is present, every FieldSet id is either explicitly specified in the file or may be inferred from a non-empty name . If the name is empty "" or missing, then the id within the file is mandatory.
If this Property is not already explicitly listed within the XML layout, we lookup the associated FieldSet in the XML layout file first matching by id using @PropertyLayout(fieldSetId=…) if any, then falling back to matching by (friendly) name using @PropertyLayout(fieldSetName=…)} if any.
We reify (in-memory) the associated FieldSet using @PropertyLayout(fieldSetId=…) (if present) as its id and using @PropertyLayout(fieldSetId=…) as its (friendly) name . While if no id is provided an id is inferred from the (friendly) name , in which case the (friendly) name must not be empty. Whereas if no (friendly) name is provided a (friendly) name is inferred from the id , in which case the id must not be empty.
With @PropertyLayout(sequence=…) the relative position within that FieldSet can be specified.
fieldSetName
Specifies the friendly-name of associated FieldSet .
Explicitly specifying an empty "" friendly-name will suppress the FieldSet 's label from being rendered.
For a more in depth description see PropertyLayout#fieldSetId() .
labelPosition
In forms, positioning of the label (left, top or none) relative to the property value.
If not specified, the default depends upon the property value’s datatype (including whether the field is #multiLine() .
multiLine
For string properties (and parameters), render as a text area over specified number of lines.
If set to > 1, then #labelPosition() defaults to LabelPosition#TOP top .
named
Name of this property (overriding the name derived from its name in code).
A typical use case is if the desired name is a reserved Java keyword, such as default
or package
.
navigable
Whether this property should be used to construct the navigable chain of breadcrumbs in the UI.
Only one property can be annotated as such per domain class.
promptStyle
How the properties of this domain object are be edited, either PromptStyle#DIALOG dialog or PromptStyle#INLINE inline .
repainting
Indicates that the value held by the property never changes over time, even when other properties of the object do change.
Setting this attribute to RepaintPolicy.NO_REPAINT
is used as a hint to the viewer to not repaint the property after an AJAX update of some other property/ies of the object have changed. This is primarily for performance, eg can improve the user experience when rendering PDFs/blobs.
Note that for this to work, the viewer will also ensure that none of the property’s parent component (such as a tab group panel) are re-rendered.
Design note: we considered implementing this an "immutable" flag on the Property annotation (because this flag is typically appropriate for immutable/unchanging properties of a domain object). However, we decided not to do that, on the basis that it might be interpreted as having a deeper impact within the framework than simply a hint for rendering.
sequence
The order of this member relative to other members in the same (layout) group, given in Dewey-decimal notation.
Also governs slot-in order for the layout group that collects all unreferenced Properties , unless overwritten via application scoped config option that enforced alphabetical order:_causeway.applib.annotation.propertyLayout.sequencePolicyIfUnreferenced_
An alternative is to use the Xxx.layout.xml
file, where Xxx
is the domain object name.
Examples
For example:
public class ToDoItem {
@PropertyLayout(
cssClass="x-key",
named="Description of this <i>item</i>",
namedEscaped=false,
describedAs="What needs to be done",
labelPosition=LabelPosition.LEFT,
typicalLength=80
)
public String getDescription() { /* ... */ }
...
}
As an alternative to using the |
The annotation is one of a handful (others including @Collection, @CollectionLayout and @Property) that can also be applied to the field, rather than the getter method. This is specifically so that boilerplate-busting tools such as Project Lombok can be used. |
Usage Notes
As alternative to using the annotation, the dynamic file-based layout can generally be used instead.
Label Positioning
The labelPosition() element determines the positioning of labels for properties.
The positioning of labels is typically LEFT
, but can be positioned to the TOP
.
The one exception is multiLine string properties, where the label defaults to TOP
automatically (to provide as much real-estate for the multiline text field as possible).
For boolean properties a positioning of RIGHT
is also allowed; this is ignored for all other types.
It is also possible to suppress the label altogether, using NONE
.
For example:
import lombok.Getter;
import lombok.Setter;
public class ToDoItem {
@PropertyLayout(
labelPosition=LabelPosition.TOP
)
@Getter @Setter
private String description;
// ...
}
Default settings
If you want a consistent look-n-feel throughout the app, eg all property labels to the top, then it’d be rather frustrating to have to annotate every property.
Instead, a default can be specified using the causeway.applib.annotation.property-layout.label-position configuration property:
causeway.applib.annotation.property-layout.label-position=TOP
or
causeway.applib.annotation.property-layout.label-position=LEFT
If these are not present then the framework will render according to internal defaults. At the time of writing, this means labels are to the left for all datatypes except multiline strings.
Prompt Style
The promptStyle() element is used to specify whether, when editing a domain object property, the new value for the property is prompted by way of a dialog box, or is prompted using an inline panel (replacing the property on the page).
If the attribute is not set, then the value of the causeway.viewer.wicket.prompt-style configuration property is used. If this is itself not set, then an inline prompt is used.
For example:
import lombok.Getter;
import lombok.Setter;
public class Customer {
@PropertyLayout(
promptStyle=PromptStyle.INLINE (1)
)
@Getter @Setter
private String notes;
// ...
}
1 | prompt for the new value for the property using an inline panel
Note that the value INLINE_AS_IF_EDIT does not make sense for properties; if specified then it will be interpreted as just INLINE . |
Text boxes
The multiLine() element specifies that the text field for a string property should span multiple lines. It is ignored for other property types.
If set > 1 (as would normally be the case), then the default labelPosition defaults to TOP
(rather than LEFT
, as would normally be the case).
For example:
import lombok.Getter;
import lombok.Setter;
public class BugReport {
@PropertyLayout(
numberOfLines=10
)
@Getter @Setter
private String stepsToReproduce;
// ...
}
Here the stepsToReproduce
property will be displayed in a text box of 10 rows.
Breadcrumbs (where am I?)
The navigable() element allows to specify a domain object’s (or view’s) navigable parent, as utilized by the 'Where am I' feature.
For example, suppose:
@DomainObject
public class Company {
// ...
}
then:
import lombok.Getter;
import lombok.Setter;
@DomainObject
public class Employee {
@PropertyLayout(navigable=Navigable.PARENT)
@Getter @Setter
private Company myCompany;
// ...
}
This points up to the Employee
's parent Company
.
For further details on using a navigable tree-structure, see Where am I in the user guide.
Descriptions
The describedAs() element is used to provide a short description of the property to the user.
In the Web UI (Wicket viewer) it is displayed as a 'tool tip'.
For example:
public class Customer {
@PropertyLayout(
describedAs = "The name that the customer has indicated " +
"that they wish to be addressed as " +
"(e.g. Johnny rather than Jonathan)")
private String firstName;
// ...
}
CSS Styling
The cssClass() element can be used to render additional CSS classes in the HTML (a wrapping <div>
) that represents the property.
Application-specific CSS can then be used to target and adjust the UI representation of that particular element.
For example:
import lombok.Getter;
import lombok.Setter;
public class ToDoItem {
@PropertyLayout(cssClass="x-key")
@Getter @Setter
private LocalDate dueBy;
// ...
}
Date intervals
The renderDay() element applies only to date properties whereby the date will be rendered as the day before the value actually held in the domain object. It is ignored for properties of other types.
This behaviour might at first glance appear odd, but the rationale is to support the use case of a sequence of instances that represent adjacent intervals of time.
In such cases there would typically be startDate
and endDate
properties, eg for all of Q2. Storing this as a half-closed interval — eg [1-Apr-2015, 1-July-2015)
— can substantially simplify internal algorithms; the endDate
of one interval will correspond to the startDate
of the next.
However, from an end-user perspective the requirement may be to render the interval as a fully closed interval; eg the end date should be shown as 30-Jun-2015
.
This attribute therefore bridges the gap; it presents the information in a way that makes sense to an end-user, but also stores the domain object in a way that is easy work with internally.
For example:
import lombok.Getter;
import lombok.Setter;
public class Tenancy {
@Getter @Setter
private LocalDate startDate;
@PropertyLayout(
renderDay = RenderDay.AS_DAY_BEFORE
)
@Getter @Setter
private LocalDate endDate;
// ...
}
Smoother UI
The repainting() element is used to indicate that the value held by the property never changes over time, even when other properties of the object do change.
Setting this attribute to true
is used as a hint to the viewer to not redraw the property after an AJAX update of some other property/ies of the object have changed.
This is primarily for performance, eg can improve the user experience when rendering PDFs/blobs.
Note that for this to work, the viewer will also ensure that none of the property’s parent component (such as a tab group panel) are re-rendered.
Design note: we considered implementing this an "immutable" flag on the @Property annotation (because this flag is typically appropriate for immutable/unchanging properties of a domain object). However, we decided not to do that, on the basis that it might be interpreted as having a deeper impact within the framework than simply a hint for rendering. |
For example:
import lombok.Getter;
import lombok.Setter;
public class Document {
@PropertyLayout(
repainting=Repainting.NO_REPAINT
)
@Getter @Setter
private Blob blob;
// ...
}
Names
The named() element explicitly specifies the property’s name, overriding the name that would normally be inferred from the Java source code.
We recommend that you only use this element when the desired name cannot be used in Java source code. Examples of that include a name that would be a reserved Java keyword (eg "package"), or a name that has punctuation, eg apostrophes. |
The name is HTML escaped.
For example:
import lombok.Getter;
import lombok.Setter;
public class ToDoItem {
@PropertyLayout(
named="Description of this item"
)
@Getter @Setter
private String description;
// ...
}
Alternatives
The framework also provides a separate, powerful mechanism for internationalization.
Hiding properties
The hidden() element attribute indicates where (in the UI) the property should be hidden from the user.
The acceptable values for the where
parameter are:
-
Where.EVERYWHERE
orWhere.ANYWHERE
The property should be hidden everywhere.
-
Where.ANYWHERE
Synonym for everywhere.
-
Where.OBJECT_FORMS
The property should be hidden when displayed within an object form.
-
Where.PARENTED_TABLES
The property should be hidden when displayed as a column of a table within a parent object’s collection.
-
Where.STANDALONE_TABLES
The property should be hidden when displayed as a column of a table showing a standalone list of objects, for example as returned by a repository query.
-
Where.ALL_TABLES
The property should be hidden when displayed as a column of a table, either an object’s * collection or a standalone list. This combines
PARENTED_TABLES
andSTANDALONE_TABLES
. -
Where.NOWHERE
The property should not be hidden, overriding any other metadata/conventions that would normally cause the property to be hidden.
The RestfulObjects viewer has only partial support for these |
Examples
For example:
import lombok.Getter;
import lombok.Setter;
public class Customer {
@PropertyLayout(
hidden=Where.ALL_TABLES
)
@Getter @Setter
private int internalId;
// ...
}
As one specific use case, if a property is annotated with @Title, then normally this should be hidden from all tables.
Annotating with @Property(where=Where.NOWHERE)
overrides this.
Alternatives
It is also possible to use @PropertyLayout#hidden to hide a property at the domain layer.
Typical (string) length
The typicalLength() element indicates the typical length of a string property. It is ignored for properties of other types.
The information is intended as a hint to the UI to determine the space that should be given to render a particular string property.
For example:
import lombok.Getter;
import lombok.Setter;
public class Customer {
@javax.jdo.annotations.Column(length=30)
@ParameterLayout(typicalLength=20)
@Getter @Setter
private String firstName;
// ...
}
All that said, the Web UI (Wicket viewer) uses the maximum space available for all fields, so in effect ignores this element. |