public interface SmartArchitecture
In a typical HTML-based web application, every time a new view is shown to a user, a round trip to the server is required to retrieve new presentation information, such as a search screen. However in an ISC-based application, showing a new view can be accomplished by simply hiding some components and showing others.
Because ISC components are expressed in a concise declarative form, and because ISC components have essentially no runtime performance impact until used, dozens of application views can be downloaded to the browser using the same bandwidth that would have been required to render just the initial view in plain HTML.
This architectural pattern of "preloading views" has tremendous benefits. View transitions which do not require new data from the server can be performed near-instantaneously and without server involvement, boosting both interactivity and scalability.
Showing a dialog containing a "wizard" is a straightforward example of showing a "preloaded view". For example:
function showNewUserWizard() { Window.create({ items:[ DynamicForm.create({ ... }) ] }); } Button.create({ title:"New User..", click:"showNewUserWizard()" });In this example, none of the components involved in a potentially multi-pane wizard are created until they are needed. Showing the wizard has near-instantaneous response and causes no server load.
However, let's say that the first pane of the wizard is going to incorporate some dynamic
user-specific data, such as the current user's name. To load the username, we'll use an RPC
operation targetting a .jsp called "getUserName.jsp" and show the wizard when it completes
(see RPCManager
for information on RPCs and how to construct a
.jsp that can
send an RPC response).
function showNewUserWizard() { RPCManager.sendRequest({ actionURL:"getUserName.jsp", callback:"doShow(rpcResponse)" }); } function doShow(rpcResponse) { Window.create({ items:[ Canvas.create({contents:"Hello, " + rpcResponse.userName}), DynamicForm.create({ ... }) ] }); } Button.create({ title:"New User..", click:"showNewUserWizard()" });In this example, we've simply incorporated a user name into the first pane of a wizard. However, this pattern allows us to arbitrarily change user interactions based on data from the server. For example, the RPCResponse might have contained a flag indicating that the wizard should skip the first two steps, or an arbitrary warning message for the user, or even JavaScript code to be evaluated on the client.
This architecture has several key advantages:
internationalization
techniques such as using JSTL tags
in a JSP remain
applicable.
{ userName : "Bob" }
.
Client Only DataSources
.
showNewUserWizard()
is
called. Subsequently we reuse the existing window, and we assume the user name has not
changed, so we need not do the RPC again. (Note: "New User" button omitted for brevity
from here on)
function showNewUserWizard() { if (!window.myWindow) { Window.create({ ID:"myWindow", autoDraw:false, items:[ Canvas.create({ ID: "welcomeCanvas" }), DynamicForm.create({ ... }) ] }); RPCManager.sendRequest({ actionURL:"getUserName.jsp", callback:"doShow(rpcResponse)" }); } else { myWindow.show(); } } function doShow(rpcResponse) { welcomeCanvas.setContents("Hello, " + rpcResponse.userName); myWindow.show(); }Batching Operations
RPCManager.startQueue
to do so.
function showNewUserWizard() { if (!window.myWindow) { Window.create({ ID:"myWindow", autoDraw:false, items:[ Canvas.create({ ID: "welcomeCanvas" }), ListGrid.create({ ID: "myGrid", dataSource:"myDataSource" }), DynamicForm.create({ ... }) ] }); RPCManager.startQueue(); myGrid.fetchData(); RPCManager.sendRequest({ actionURL:"getUserName.jsp", callback:"doShow(rpcResponse)" }); RPCManager.sendQueue(); } else { myWindow.show(); } } function doShow(rpcResponse) { welcomeCanvas.setContents("Hello, " + rpcResponse.userName); myWindow.show(); }Segmenting very large Applications
If an application has many hundreds of views, but only a handful of views are used by a given user in a typical session, for the fastest loading performance you should consider loading only the most commonly used views initially then loading further views on demand.
You can use FileLoader.loadJSFiles to load a set of JavaScript files compromising an application module that defines a set of related views. The loaded JavaScript files may define new component classes and new DataSources in addition to defining new views and their associated logic.