Jello's RESTful API together with it's powerful authorization model makes it an ideal framework for developing web services. Developing a front-end user interface is the next logical step towards a complete end-to-end application.
With Jello, you can choose (or mix) between several implementation options. From instant, out-of-the-box data views, to pixel perfect UI.
Jello offers a unique out-of-the-box data views feature in addition to the OData protocol.
By simply replacing the protocol /jello/data/
prefix with /jello/view/
you will get UI views so you can test your application and start to interact with the data instantly.
These views can also serve as Admin UI and can be easily extended by adding custom controls.
- $showRecordDetail
- $embeddedRecordDetail
- $embeddedRecordDetail image|fileName|fileSize|key
- $resourcePath
By using jello.ux
annotations, you can append UX metadata to your elements.
This additional information will be exposed in the metadata document via REST calls.
Jello Views supports the following core UX annotations:
Provide a label for entities, fields, enumerations, and actions' parameters.
Example:1 2 | @Label("Release year") private Integer year; |
Provides a hint for fields and actions' parameters.
Example:1 2 | @Hint(value="Must be unique", displayAs=Display.PLACEHOLDER) private String licensePlate; |
Jello data form validates field values based on the field data type. In addition, you can specify more validations such as min/max for numbers, min/max length for strings, and special patterns such as url or email.
Example:1 2 3 4 5 | @Validation(min=0,max=1000) public Double price; @Validation(email=true) public String email; |
By adding @Control
annotation to a field or action's parameter,
you can hide specific controls or bind a field to a control type other than the default one associated with the field type.
This non-default control can be either a Jello UX extension control or a custom control.
Jello UX extension controls:
- prefixed with jello.ux.controls.
- Currently supported:
jello.ux.controls.TreeSelector
jello.ux.controls.TextareaCtrl
jello.ux.controls.RatingControl
jello.ux.controls.CheckboxCtrl
Custom controls:
- Absolute path to the control resource.
- See Custom controls for more details.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | @Control(hide=true) public String preview; @Control(src="/demo/custom/ratingControl") Integer rating; @Expose @Reference(Category.class) @Control( //Using jello tree selector control instead of the default dropdown src="jello.ux.controls.TreeSelector", // Applies only for data form, not data table containerRole=ContainerRole.FORM, settings={ "parent:parent", "children:children", "label:name", "icon:icon" } ) public Key category; @Control(src="jello.ux.controls.TextareaCtrl", settings={"rows:5"}) public String comment; |
Conditional state:
Sometimes it is desired to hide or disable control based on a dynamic value from another field. Such behavior can be defined by using one of the @Control hideIf, showIf, enableIf, disableIf
optional fields with the following syntax:
@Control(hideIf|showIf|disableIf|enableIf="JS-EXPRESSION")
1 2 3 4 5 6 7 8 | @Control(hideIf="rating == 3") public Boolean hideIfRating3; @Control(showIf="color == 'GREEN'") public Boolean showOnlyIfColorGreen; @Control(enableIf="color == 'GREEN' && year > 1990") public Boolean enableOnlyIfColorGreenAndYearBT50; |
@View
annotations can serves two purposes:
jello.
@View(name="cheapests", filter="price<20", top=10) @View(name="totalOrders", control="/demo/custom/chart/ChartView", select="name as label, totalSales as value") public class Product extends JelloEntity { @View(name="customMap", control="/demo/custom/mapView", expand="address", settings={"lat:address.lat", "lng:address.lng", "label:name", "marker:photo"}) @View(name="jelloMap", control="jello.MapView", expand="address", settings={"lat:address.lat", "lng:address.lng", "label:name", "marker:photo"}) @View(name="withAudit", audit=true) public class Supplier2 extends JelloEntity {
Referring to entitie's view via OData is done with the following syntax
../jello/[data|view|meta]/namespace/entity::view-name
http://localhost:8888/jello/view/demo.map/Supplier::jelloMap http://localhost:8888/jello/view/demo.catalog/Product::cheapests
Annotate an embedded field type with @Summary
will hint the client how to render the field value in case only a summary is needed.
1 2 3 4 5 6 7 8 9 | @Summary("street + ',' + city + ' ' + zipCode + ',' + state") Address address; class Address extends JelloEntity { @Expose String street; @Expose String city; @Expose String state; @Expose String zipCode; } |
By default, Jello Views (JelloDataTable
and JelloDataForm
) will bind the data elements to the built-in Jello UX controls according to the element's type.
Here is the list of built-in controls:
InputCtrl
, CheckboxCtrl
, EnumSelector
, TextareaCtrl
,
Reachtext
, AttachmentCtrl
, RefSelector
,
CollectionCtrl
, AssociationCtrl
, ComplexCtrl
TreeSelector
, RatingControl
, DynamicCtrl
.
By default, Jello Views will bind the data elements to the built-in Jello UX controls according to the element's type.
You can change this behavior by providing custom controls that implement the JelloControl
JavaScript interface and then add @jello.ux.Control
annotation to the element you want to bind the new control to.
First, you will need to provide a JavaScript
control that implements the JelloControl interface.
You can write this control from scratch or just wrap a 3rd party control with a JelloControl interface.
Add the new control file to the war
folder and make sure it is accessible via an HTTP request. The name of the js file should be the same as the name of the control class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | // js file name should be the same as the name of the control name. // Control's constructor gets the parent container id, a settings object, and the field metadata. function controlName( containerId, settings, filedDef ); // The render method gets a callback to be called once the control is ready and has been // appended to the parent container. The method should empty the parent container before // appending the control. The callback takes the newly created control object as its only argument. render( onReadyCB ); // Return the current value. getValue( ); // Set the control value. setValue( value ); // Bind an event listener function to be called on change event. // the following parameters should be passed to the listener function in this order: // the original triggered event, the control object, the current value. change( listener ); // Make the control disabled or enabled. setDisabled( true|false ); } |
@Control(src=controlFilePath[, settings={"propName1 : value1,...,"}]) (jello.ux.Control)
Add this annotation to an element you wish to bind to a custom control. This annotation gets two input parameters:
- src
: relative path to the control js file (omit the .js suffix)
- settings
(optional): an array of strings in which each string contains the property's key and value in the format of "propName : value".
JelloTableView makes use of the width
property but with this parameter, you can pass any custom property to be handled by the custom control.
Consider the following example of Rating custom control. The control name is ratingControl and the file name will be ratingControl.js (refer to the Custom Control - case study to see complete code).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | function ratingControl( containerId, settings, filedDef ) { this.container = $('#' + containerId); this.settings = settings; this.render = function(onReady) { ... onReady(this); } this.getValue = function() { ... } this.setValue = function( value ) { ... } this.change = function(listener) { ... } this.setDisabled = function(state) { ... } } |
Here is what the @Control
annotation will look like:
1 2 3 | @Expose @Control(src="/demo/custom/ratingControl", settings= {"width:150px"}) public Integer rating; |
And here is the view:
Check the demo and see to the complete Custom Control - case study.
By default, Data Table view is used to display a records list.
You can change this behavior by providing custom view control that implements the JelloViewControl
JavaScript interface
and then add @jello.ux.View
annotation to the entity you want to bind the new view to.
First, you will need to provide a JavaScript
control that implements
the JelloViewControl interface.
You can write this control from scratch or just wrap a 3rd party control with a JelloViewControl interface.
Add the new control file to the war
folder and make sure it is accessible via HTTP request.
The name of the js file should be the same as the name of the control class.
1 2 3 4 5 | // js file name should be the same as the name of the control name. // Control's constructor get the parent container id, the view data, and a settings object. function ChartView( containerId, data, settings ) { // create custom view and append it to parent container. } |
@View(view="view-name", src=controlFilePath[, settings={"propName1 : value1,...,"}]) (jello.ux.View)
Add this annotation to an entity you wish to bind to a custom view.
- src
: relative path to the control js file (omit the .js suffix)
- settings
(optional): an array of strings in which each string contains the property's key and value in the format of "propName : value".
See Custom map view control code sample.
In addition to the core jello.ux annotations, you can define custom annotations. Any custom annotation annotated with jello.ux.UXAnnotation will be exposed in the metadata document via REST call and therefore can be used to pass custom metadata to the client application.
Example:package demo.ux; @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD }) @UXAnnotation public @interface Link { public static final String Popup = "Popup"; public static final String NavigateTo = "NavigateTo"; String behavior() default Link.NavigateTo; }
@Link(behavior=Link.Popup) public String supplierSiteUrl;
{ name: "supplierSiteUrl", demo.ux.Link: { behavior: "Popup" }, type: "String" }
Jello OData protocol is JSON based and includes comprehensive support for pagination, records count, data expands, and some unique features such as data preview and more. Thus, consuming these services by a custom front-end user interface becomes a straightforward task.
Jello provides the following data view APIs:
Required: //jello-framework.com/apis/v-1.2.8/assets/js/jelloDataView.min.js
- $JELLO.getMetadata(entity, settings)
- $JELLO.getMetadataAsync(entity, callback, settings)
- $JELLO.getEntityListAsync(namespace, callback)
- $JELLO.getNSListAsync(callback, expand)
- jelloDataTable(containerId, entityMetadata, settings)
- jelloDataForm(containerId, entityMetadata, settings)
See Client API for more details.
Check the Jello Modules tutorial to learn how to create and consume Jello Modules.
Was this page helpful? Let us know how we did:
Last updated March 20, 2019.