Namespace: ojModule

Oracle® JavaScript Extension Toolkit (JET)
2.2.0

E79261-01

QuickNav

Fields

ojModule

Version:
  • 2.2.0

ojModule binding for Knockout.js manages content replacement within a particular region of the page. The binding can be used to implement navigation within a region of a single-page application.

Terminology

  • View - the HTML markup to be displayed within the page fragment. The markup can contain Knockout bindings, which will be automatically activated after the View is attached to its container.
  • ViewModel - optional ViewModel that will be applied by Knockout to the View
  • Module - a combination of View and ViewModel

Supported Features

  • ViewModel and View definitions loaded using require.js
  • Ability to provide a ViewModel by supplying a factory instance
  • View Caching
  • Ability for a ViewModel to create a View
  • Notifications about the lifecycle events (Module activation and deactivation, attaching and detaching DOM, applying bindings)

Examples

<!-- Simple module binding with the currentCenter observable containing the name of the ViewModel, 
     which is also used as the name of the View -->
<div data-bind="ojModule: currentCenter"></div>

<!-- Module binding on the comment node -->
<!-- ko data-bind="ojModule: currentCenter" --><!-- /ko -->

<!-- Module binding with a LifecycleListener -->
<div data-bind="ojModule: {name: currentCenter, lifecycleListener: moduleLifecycle}"></div>

<!-- Module binding with caching -->
<div data-bind="ojModule: {name: currentName, cacheKey: currentName}"></div>

<!-- View-only module binding -->
<div data-bind="ojModule: {viewName: currentName}"></div>

Conventions

  • ViewModel modules will have .js extension, and Views will have .html extension
  • ViewModel modules are expected to be found under the 'viewModels/' folder, and Views are expected to be found under the 'views/' folder. Both viewModels and /views folders are expected to be in the 'base' RequireJs folder (usually js/)
  • Optional 'initialize' and 'dispose' functions will be invoked on the ViewModel after it is created or before it is destroyed respectively. See ConventionMethods for method definitions
  • Optional lifecycle event handlers can be implemented by the ViewModel as well. See ConventionMethods for method definitions
  • .
For information to modifying the convention defaults see oj.ModuleBinding

ViewModel's Lifecycle

The instance of the ViewModel is established as follows:
  1. If the viewModelFactory is provided, the 'starter' object is determined by resolving a Promise returned by the factory's createViewModel() method. Otherwise, the 'starter' object will be assigned the return value of the AMD module specified by the 'name' option on the binding (if present)
  2. If the 'starter' object is a function, it will be treated as a constructor that will be invoked to create the ViewModel instance, and the 'params' object specified by the binding's 'params' option will be passed into the constructor function as a parameter. Otherwise, the initialize convention method will be invoked on the 'starter' instance. If the method does not return anything, the 'starter' object will be treated as the ViewModel instance. Otherwise, the return value will become the ViewModel instance.
ViewModel's dispose convention method will be invoked before binding's references to the ViewModel instance are released. The following lifecycle listeners are supported on a ViewModel instance as convention methods:

Acessing ViewModel Data

The instance of the ViewModel will be applied to the View, i.e. it will serve as View's default data object. The same instance will also be available as $module within Knockout binding expressions (this may be useful for accessing module's ViewModel in foreach iterators). For the View-only modules, the default data object will be null. Parent ViewModel will be available as $parent.

Avoiding Mutiple re-renders

This binding keeps track of changes to each of its options. If an observable holding an option value is mutated, the view will be re-rendered. One of the following approaches may be used to avoid unnecessary re-renders:
  • Use a single observable to store the entire binding value with all attributes:

    this.moduleValue = ko.observable({name: 'acc_details', cacheKey:'acc'});
    ...
    <div data-bind="ojModule: moduleValue"></div>
    

  • Use the same observable for the name and cacheKey attributes:

    this.moduleName = ko.observable('acc_details');
    ...
    <div data-bind="ojModule: {name: moduleName, cacheKey: moduleName}}"></div> 
    

  • Use rate-limiting for the observables referenced by the binding:

    this.moduleName = ko.observable('acc_details').extend({ rateLimit: 1 });
    this.cKey = ko.observable('acc').extend({ rateLimit: 1 });
    this.vName = ko.observable('accView').extend({ rateLimit: 1 });
    ...
    <div data-bind="ojModule: {name: moduleName, cacheKey: cKey, viewName: vName}}"></div>
    ...
    // Mutating multiple observables independently is OK when they use a rate limit extender
    this.moduleName('preferences');
    this.cKey('prefs');
    this.vName('prefsView);
    

Id Uniqueness for View Content

ß ojModule does not modify any HTML Ids specified within the Views. The application is responsible for avoiding Id conflicts. Possible cases to consider are:
  1. Conflicts with Ids used on the hosting page
  2. Conflicts caused by multiple instances of the same View within the HTML document
  3. Conflicts during animated View transitions (both Views are attached to the document for the duration of transition)
  4. Conflicts with the cached View content when ojModule's 'cacheKey' option is set. ojModule currently keeps cached Views in the hidden subtree within the same HTML document
All cases above except case (2) can be solved by adopting a convention-based prefix for each View. For example, all Ids in the 'Accounts' View would start with 'ac_', all Ids in the 'Preferences' View would start with 'pr_', etc. Case (2) would require the use of Ids that would dynamically bound at runtime. The application could pass a unique Id prefix to each incarnation of the View using the 'params' option.

Using ojModule with Require.js

Request ojs/ojmodule module before Knockout bindings are applied

Source:

Fields

Options

Properties:
Name Type Description
name string ViewModel name. Required if viewModelFactory parameter is not specified. The name will be used to load an AMD module containing the definition of the ViewModel. If the module returns a function, it will be used as a ViewModel constructor, and any other return value (including null) will be treated as a ViewModel instance. If the entire binding's value is a string, it will be treated as a 'name' option. If you need to create a view-only module, use the viewName option
viewName string View name. If omitted, the name of the View is assumed to be the same as the name of the VewModel.
viewModelFactory Object instance of the factory that implements createViewModel(params, valueAccessor) method. The method has to a return a Promise that will resolve to the ViewModel instance or constructor.
params Object object that will be passed into the ViewModel constructor or the createViewModel method of the View Model factory as a parameter. The object will be available as $params within the View's Knockout binding expressions.
createViewFunction string name of the ViewModel function used to create a View. If this parameter is specified, the ViewModel will be responsible for providing the definition of the View. The function has to return a Promise that will be resolved to document fragment, an array of DOM nodes or a string containing the HTML
cacheKey string The key used to cache the View after it is no longer displayed. Setting this parameter will enable View caching. When the View is about t be cached, its Knockout bindings will not be deactivated when the View is removed from DOM tree. The cache will be discarded after when the window object is destroyed or when the ojModule binding instance is deactivated. Since changes to any binding option will re-render the view, it is very important that cacheKey and the rest of the options are applied atomically. Failure to do so will result in a wrong cached view being retrieved. See the 'Avoiding Multiple Re-renders' section above.
lifecycleListener Object An instance of the object implementing one or more methods defined by the LifecycleListener duck-typing interface.
animation Object instance of the ModuleAnimation duck-typing interface that will manage animation effects during View transitions.
Source: