Skip to end of metadata
Go to start of metadata

What is Angular?

AngularJS is a structural framework for dynamic web apps. It lets you use HTML as your template language and lets you extend HTML's syntax to express your application's components clearly and succinctly. Out of the box, it eliminates much of the code you currently write through data binding and dependency injection. And it all happens in JavaScript within the browser making it an ideal partner with any server technology.

For more information, see http://angularjs.org/ and http://egghead.io/

KRAD and AngularJS

Some features of AngularJS, in particular the binding functionality, will enhance KRAD nicely. Currently to do 'partial' updates of the page you either do a component refresh or need to manually update the DOM with custom script. Using AngularJS we can easily keep the entire client up to date as changes are being made. In particular for applications that are more rich (less CRUD based, like for example MyPlan) this will have real benefit.

It should be noted though that AngularJS is not just a small JS library that adds on some widgets, but a full 'end to end' solution, or web framework. Therefore it might be too heavyweight for adding onto to KRAD for a subset of the features. For example, it is more geared towards single paged applications, although it states it can be used with multi-page applications. We will need to perform performance testing in regards to the initial DOM parsing and linking AngularJS does and the cost of doing that for each page render (for typical single paged applications this is only done once).

There are many other features that could be used (controllers, templates, model handling) but these are already supported by KRAD. This document does not go into analysis of which way is 'better', merely that the features are redundant (and the recognition that changing to use the AngularJS way would require lots of rewrite and unknowns in terms of enterprise development). Applications may choose to use these other AngularJS features, but the KRAD specific functionality (for example controller methods) will not be provided using this strategy. 

Bootstrapping

The angular.js dependency will be added to the base KRAD theme and available to all views by default.

KRAD will also add the ngApp and ngController directives.

ngApp

The ngApp directive will be added to the html tag:

KRAD will also create the app variable in krad.initialize.js:

Applications can then add filters, directives, and services in common JS files or JS files for a specific view:

ngController

The ngController directive will be added to the 'Uif-ApplicationView' div tag (which surrounds all the view content) and will be named from the view id:

Applications should then initialize the controller in one of their script files:

To pick up the data that KRAD has bootstrapped from the server form, a call to getClientSideModel() should be made:

Data Binding

Properties will be added to KRAD components for exposing bindings and expressions to AngularJS.

Input and Data Fields

boolean clientSideModel - indicates whether the model property pointed to by the input/data field should be exposed in the client side model

Ex. Input Field

Rendered Markup:

Note: data-ng-model added to other control types in a similar manner

Ex. Data Field

Rendered Markup:

For all the input/data fields that are marked with clientSideModel, KRAD will created the client side model object including these properties (see Bootstrapping). The client side model will be initialized to the server side form values when the view is rendered.

For model state that is only present on the client (not on the server side form), support will need to be added for not requiring the propertyName on input and data fields. In these cases it will be assumed the model attribute is getting initialized by custom script:

Ex. Input Field Client Only

Rendered Markup:

Expressions

AngularJS expressions will be supported for UIF component properties that produce text. These will be created by using the AngularJS expression syntax {{expression}}. The properties that may contain these expressions are (others can be added as needed):

  • Header Text
  • Labels
  • Any Message Component
  • Link Text
  • Link Source (creates ngHref)
  • Image Source (creates ngSrc)
  • Data Attributes (values, can be used for any ng attribute, for example ngClass, ngClick, ...)

Ex. Header Text

Rendered Markup:

In this example (assuming bookTitle is bound to an input field), as the book title is modified by the user the header text will reflect the updated title.

Ex. Message

Rendered Markup:

KRAD will collect all the properties referenced in client side bindings and expose those as client side model attributes (and expose as described in the previous section).

Filters

Filters in AngularJS can be used to transform a value or filter a list. This is an area where there is overlap with current KRAD functionality. KRAD has various support for transforming (or formatting) values for display. However, one gap currently is formatting values that are created on the client (for example client side totaling). The use of AngularJS filters might fill that gap. However, we would need to determine if we will duplicate things like formatters on the server and client and consider locale support.

The other significant use case of filters is for filtering lists client side. Within data tables or grids (like the MyPlan filtering) is where this functionality could be very useful, however KRAD currently uses DataTables which has built-in support for client side filtering. Moving to using AngularJS would require recreating the other DataTables functionality (sorting, paging, export, etc). This being said, there might be some use for creating simple lists and using AngularJS list filtering. We can also look into a plugin for DataTables that integrates with AngularJS: http://www.datatables.net/

Filters for Formatting

Filters can be given with Angular expressions defined in the UIF (see example in Expressions).

List Filters

To support list filters and dynamic list building client side a new type of group component will be created.

RepeatGroup (Uif-RepeatGroup)

The repeat group will extend the base group component and provide list functionality built client side (using the AngularJS ngRepeat directive). The components held by the group will provide the initial template to iterate over (after being rendered server side). They may contain expressions (as described in the Expression section) that will be bound client side.

KRAD will expose the properties referenced in the repeat group expression in the client side model.

Properties

clientSideExpression - the expression that will be evaluated for repeating the content (can also include filters)

items (inherited from Group) - the components that will repeated

layoutManager (inherited from ContainerBase) - the layout of the components within a 'row'. The layout also determines how the group will be wrapped (table for grid layout, div for box layout, ul for list layout)

cssClasses (inherited from ComponentBase) - css classes (and styles) will be applied to the wrapping element (table, div, or ul)

By default the group header and footer will not be enabled for repeat groups.

Ex.

Rendered Markup (not exact for data field markup):

Directives

Directives allow HTML to be extended (for example with new elements or attributes, a concept similar to Web Components). Directives can transform the DOM or add behavior to an element. With this ability directives can be used to build reusable widgets or components. AngularJS comes with many directives out of the box, and allows developers to create new directives.

In terms of AngularJS and KRAD, this is an area of overlap. The KRAD UIF is built around the concept of building components that are easily reused and customized in applications (without impacting upgrade paths). Therefore in general creation of custom directives is not recommended for KRAD applications. However, if use cases do arise where custom directives might provide value, there are mechanisms currently in KRAD that can be used.

Use of Directives as Attributes

To use a directive as an attribute, the UIF component Map property dataAttributes can be used. All map entries end up becoming data-key="value" attributes on the corresponding element.

Ex. 

Rendered Markup:

Use of Directives as Classes

To use a directive as a class, the component property cssClasses can be used.

Use of Directives as Elements

To use a directive as an element, a message component can be created:

Rendered Markup:

Or, a KRAD component can be created that renders the custom element (better for reuse/sharing).

Note the method shown here for using custom directives can also be used for AngularJS directives not supported in KRAD by other means. Custom directives can be created as described in the section Bootstrapping.

ngView and Routes

AngularJS allows bringing in other templates into the page through routes (URL paths). Although the recommendation is to use the standard KRAD navigation and controllers (at least medium and large applications), the feature could be beneficial for making small updates to the UI without leaving the page (although it is a bit redundant with KRAD progressive disclosure and component refresh support).

To create the ngView templates, hidden groups should be defined in the KRAD view. The content can then be retrieved and associated with the route through the Angular app config.

Application JS:

Note getHtml is a KRAD helper method that will get the contents of the element with the given identifier using jQuery.

Live Panel and Card Layout

With AngularJS backing, some interesting things are possible without too much effort. This includes a new component type and layout manager inspired from the ngView concept.

Live Panel

Using AngularJS bindings/expressions, the live panel would allow a groups contents to be updated client side. Example use could be a detail panel that shows details for a record when the user clicks a link, or mouses over a row. Using some of the previous mentioned support and a few helper JS methods this would be trivial to implement in a view.

For example, suppose we had a group that displayed details about a book. We would define the book group as usual and expose in the client side model as described previously in this document. Now instead of using one of the standard UIF groups, we would use the LivePanelGroup:

The live panel group will use a default vertical box layout manager but this could be changed using the layoutManager property.

The framework will implicitly create a binding object for the live panel group that can be used to change the panel contents client side. Note we can include message components with Angular expressions or embedded HTML for more sophisticated live panels.

We can then trigger the update on a panel with the helper method updatePanel('panelId', bindingObject). For example in the repeat group created above we can add mouse over script on the book id that will update the book details panel:

Card Layout

Currently in KRAD you can have multiple groups with progressive disclosure conditions. When one groups condition becomes false and the other becomes true, assuming they are after each other in the DOM they can appear to exchange places. However there is not true support for replacing the contents of a position (similar to the ngView).

The CardLayout would contain one or more configured groups (called cards) of which only one will be displayed at a time. When the display of one card is triggered, it would take the place of the previously displayed card (or group). (Note: this is basically like the TabGroup except the user does not have controls to switch the displayed group, and similar to the AngularJS ngView except multiple card layouts could be present on a page).

For example, suppose when the page is initially rendered we want to display a message about no items being selected. Then when the user clicks the add link for one of the search results the message is replaced with the details for that book:

This can be done by setting up a card layout:

By default the first group contained in the card group will initially display. This can be modified by setting the render/progressiveRender conditions on the contained groups.

The card which is being displayed can be modified client side by calling the script method showCard('cardGroupId', 'cardId'), or adding the data attribute 'showCard' to a link/button (which will setup a click event):

Full Example

The following is a rough mapping of a screen written with pure HTML/AngularJS to KRAD. 

Original Version

Html
Script

KRAD Version

XML
JavaScript

Note the KRAD version could be simplified further by introducing new components. For example the entire search box and results could become a component. If the view was common enough, a new view type could be created that would greatly reduce the amount of configuration. In addition, in the context of an application there would likely be a data dictionary file for the Session data object that would contain the label, control, validation, etc., so those properties could be removed from the view.

Other

Other areas to investigate include:

Progressive Disclosure/Component Refresh

Currently KRAD provides progressive disclosure and component refresh functionality by translating Spring EL expressions to JavaScript expressions evaluated client side. If we brought in AngularJS we should look at how the two relate. That is whether we can reuse AngularJS for evaluating these conditions and/or augment the support to be able to take advantage of the exposed client side model, filters and so forth.

Summary

 A few things should be noted in regards to bringing in AngularJS support:

  1. There are some really nice features of AngularJS that will make adding client side functionality much easier. However there is a lot of overlap with KRAD as well, so we will need to determine if the overhead is worth the benefit
  2. If out of the box support was not added, applications could still take advantage of AngularJS within KRAD (the support of dataAttributes makes this possible)
  3. The most appealing feature is the ease for creating dynamic bindings and expression support. For some applications this might be of great value, but for others very little. If the overhead of AngularJS is too much, we can add similar support just for this aspect in KRAD (possibly with use of Backbone). 
  4. An upcoming work item is for event support (https://wiki.kuali.org/display/KULRICE/UIF+Eventing+Framework), we should look at how this work fits in with that need
  • No labels