5 Create Single-Page Apps

Oracle JET includes the oj-module component and CoreRouter framework class that you can use to create single-page apps that simulate the look and feel of desktop apps.

Design Single-Page Apps Using Oracle JET

Oracle JET includes Knockout for separating the model layer from the view layer and managing the interaction between them. Using Knockout, the Oracle JET oj-module component, and the Oracle JET CoreRouter framework class, you can create single-page apps that look and feel like a standalone desktop app.

Understand Oracle JET Support for Single-Page Apps

Single-page apps (SPAs) are typically used to simulate the look and feel of a standalone desktop app. Rather than using multiple web pages with links between them for navigation, the app uses a single web page that is loaded only once. If the page changes because of the user's interaction, only the portion of the page that changed is redrawn.

Oracle JET includes support for single page apps using the CoreRouter class for virtual navigation in the page, the oj-module component for managing view templates and viewModel scripts, and Knockout for separating the model layer from the view layer and managing the binding between them. In the Oracle JET Cookbook, you can view a number of implementations that use the CoreRouter class. These implementations range from the simple, that switch tabs, to more complex examples that use parameters and child routers. See the CoreRouter demo in the Oracle JET Cookbook.

When routing a single-page app, the page doesn't reload from scratch but the content of the page changes dynamically. In order to be part of the browser history and provide bookmarkable content, the Oracle JET CoreRouter class emulates the act of navigating using the HTML5 history push state feature. The CoreRouter also controls the URL to look like traditional page URLs. However, there are no resources at those URLs, and you must set up the HTML server. This is done using a simple rule for a rewrite engine, like mod rewrite module for Apache HTTP server or a rewrite filter like UrlRewriteFilter for servlets.

In general, use query parameters when your app contains only a few views that the user will bookmark and that are not associated with a complex state. Use path segments to display simpler URLs, especially for nested paths such as customers/cust/orders.

The Oracle JET Cookbook uses the Oracle JET oj-module feature to manage the Knockout binding. With oj-module, you can store your HTML content for a page section in an HTML fragment or template file and the JavaScript functions that contain your viewModel in a viewModel file.

When oj-module and CoreRouter are used in conjunction, you can configure an oj-module object where the module name is the router state. When the router changes state, oj-module will automatically load and render the content of the module name specified in the value of the current RouterState object.

Create a Single-Page App in Oracle JET

The Oracle JET Cookbook includes complete examples and recipes for creating a single-page app using path segments and query parameters for routing and examples that use routing with the oj-module component. Regardless of the routing method you use, the process to create the app is similar.

To create a single-page app in Oracle JET:

If needed, create the app that will house your main HTML5 page and supporting JavaScript. For additional information, see Understand the Web App Workflow.

  1. Design the app's structure and identify the templates and ViewModels that your app will require.

  2. Add code to your app's main script that defines the states that the router can take, and add the ojs/ojcorerouter module to your require() list.

  3. Add code to the markup that triggers the state transition and displays the content of the current state.

    When the user clicks one of the buttons in the header, the content is loaded according to the router's current state.

    For additional information about creating templates and ViewModels, see Use the oj-module Element.

  4. To manage routing within a module, add a child router using CoreRouter.createChildRouter().

  5. Add any remaining code needed to complete the content or display.

See the CoreRouter demo in the Oracle JET Cookbook that implements CoreRouter and provides a link to the API documentation.

Use the oj-module Element

With the oj-module element, you can store your HTML content for a page section in an HTML fragment or template file and the JavaScript functions that contain your viewModel in a viewModel file.

Many of the Oracle JET Cookbook and sample apps use oj-module to manage the Knockout binding.

To use oj-module in your Oracle JET app:

If needed, create the app that will house your main HTML5 page and supporting JavaScript. See Understand the Web App Workflow. Oracle JET apps are built with default views and viewModels folders under app_folder/src/js.

  1. In your RequireJS bootstrap file (typically main.js) add ojs/ojmodule-element to the list of RequireJS modules, along with any other modules that your app uses.

    require(['knockout', 'ojs/ojmodule-element-utils', 'ojs/ojcorerouter', 'ojs/ojlogger'', 'ojs/ojresponsiveknockoututils'  
    'ojs/ojarraydataprovider', 'ojs/ojoffcanvas', 'ojs/ojknockouttemplateutils', 'ojs/ojmodule-element', 'ojs/ojknockout', 
    'ojs/ojbutton', 'ojs/ojmenu', 'ojs/ojmodule', 'text', 'ojs/ojcheckboxset', 'ojs/ojswitch']
  2. Create your view templates and add them to the views folder as the default location.

  3. Create your viewModel scripts and add them to the viewModels folder as the default location.

  4. Add code to the app's HTML page to reference the view template or viewModel in the oj-module element. To obtain the router configuration, set the config attribute of the oj-module element to the koObservableConfig observable created by the ModuleRouterAdapter.

    <oj-module role="main" class="oj-panel" style="padding-bottom:30px" config="[[moduleAdapter.koObservableConfig]]"></oj-module>

For more information about CoreRouter and oj-module, see the Oracle JET CoreRouter and oj-module API documentation.

Tip:

oj-module is not specific to single-page apps, and you can also use it to reuse content in multi-page apps. However, if you plan to reuse or share your content across multiple apps, consider creating Oracle JET Web Components instead. Web Components are reusable components that follow the HTML5 Web Component specification. They have the following benefits:

  • Web Components have a contract. The API for a Web Component is well defined by its component.json, which describes its supported properties, methods, and events in a standard, universal, and self-documenting way. Providing a standardized contract makes it easier for external tools or other apps to consume these components.

  • Web Components include version and dependency metadata, making it clear which versions of Oracle JET they support and what other components they may require for operation.

  • Web Components are self-contained. A Web Component definition can contain all the libraries, styles, images, and translations that it needs to work.

To learn more about Web Component features, see Work with Oracle JET Web Components.

Work with oj-module’s ViewModel Lifecycle

The oj-module element provides lifecycle listeners that allow you to specify actions to take place at defined places in the ViewModel’s lifecycle.

For example, you can specify actions to take place when the ViewModel is about to be used for the View transition, after its associated View is inserted into the document DOM, and after its View and ViewModel are inactive.

The following table lists the available methods with a description of their usage.

Method Name Description

connected()

The optional method will be invoked after the View is inserted into the DOM.

This method might be called multiple times:

  • after the View is created and inserted into the DOM

  • after the View is reconnected after being disconnected

  • after a parent element (oj-module) with attached View is reconnected to the DOM

transitionCompleted()

This optional method will be invoked after transition to the new View is complete. This includes any possible animation between the old and the new View.

disconnected()

This optional method will be invoked when the View is disconnected from the DOM.

This method might be called multiple times:

  • after the View is disconnected from the DOM

  • after a parent element (oj-module) with attached View is disconnected from the DOM

You can also find stub methods for using the oj-module lifecycle methods in some of the Oracle JET templates. For example, the navbar template, available as a template when you Scaffold a Web App, defines stub methods for connected(), disconnected(), and transitionCompleted(). Comments describe the expected parameters and use cases.

function DashboardViewModel() {
      var self = this;
      // Below are a set of the ViewModel methods invoked by the oj-module component.
      // Please reference the oj-module jsDoc for additional information.

      /**
       * Optional ViewModel method invoked after the View is inserted into the
       * document DOM.  The app can put logic that requires the DOM being
       * attached here. 
       * This method might be called multiple times - after the View is created 
       * and inserted into the DOM and after the View is reconnected 
       * after being disconnected.
       */
      self.connected = function() {
        // Implement if needed
      };

      /**
       * Optional ViewModel method invoked after the View is disconnected from the DOM.
       */
      self.disconnected = function() {
        // Implement if needed
      };

      /**
       * Optional ViewModel method invoked after transition to the new View is complete.
       * That includes any possible animation between the old and the new View.
       */
      self.transitionCompleted = function() {
        // Implement if needed
      };
    }

    /*
     *   Returns an instance of the ViewModel providing one instance of the ViewModel. If needed, 
     *   return a constructor for the ViewModel so that the ViewModel is constructed
     *   each time the view is displayed.
     */
    return DashboardViewModel;
  }

For more, see the oj-module API documentation.