OJET: Module Not Found Handling

Hello Oracle JET lovers,

In this post I will bring a small example on how to handle two common errors when Routing in Oracle JET.
  1. Routing to a State Id which has not been registered as part of the Router configuration
  2. Routing to an existing State Id, however when calculating the corresponding View and View Model they are missplaced, no-exist or whatever cause it makes the module to do not load properly
The example is based on the scaffold Oracle JET Application navdrawer (without TypeScript).

GitHub: ojet-page-not-found-handling

Taking a look into the code provided by navdrawer, navigation is implemented as following:
  • The index.html uses oj-navigation-list where selection is bind to router.stateId which will immediately trigger the Router to route to the new stateId

    
    
  • The appController.js (View Model for the index.html) configure the possible Router States

    // Router setup
           self.router = oj.Router.rootInstance;
           self.router.configure({
             'dashboard': {label: 'Dashboard', isDefault: true},
             'incidents': {label: 'Incidents'},
             'customers': {label: 'Customers'},
             'about': {label: 'About'}
           });
          oj.Router.defaults['urlAdapter'] = new oj.Router.urlParamAdapter();
  • In addition, it configures an array for drawing the navigation. This separation is done because maybe you do not want to render all possible states of a Router in a navigation.

    // Navigation setup
          var navData = [
          {name: 'Dashboard', id: 'dashboard',
           iconClass: 'oj-navigationlist-item-icon demo-icon-font-24 demo-chart-icon-24'},
          {name: 'Incidents', id: 'incidents',
           iconClass: 'oj-navigationlist-item-icon demo-icon-font-24 demo-fire-icon-24'},
          {name: 'Customers', id: 'customers',
           iconClass: 'oj-navigationlist-item-icon demo-icon-font-24 demo-people-icon-24'},
          {name: 'About', id: 'about',
           iconClass: 'oj-navigationlist-item-icon demo-icon-font-24 demo-info-icon-24'}
          ];
          self.navDataProvider = new ArrayDataProvider(navData, { keyAttributes: 'id' });
If you check the Oracle JET documentation, you will find that Router.go method returns a Promise. It means, a rejection can be catch for handling Routing issues.

In addition, navdrawer uses moduleUtils module from ojs/ojmodule-element-utils for loading the View and ViewModel required by the oj-module.
Checking the source code of ojs/ojmodule-element-utils you can easily see that also a Promise is returned in both methods.

Taking the above information I have modified a bit the code of index.html and appControlller.js for loading a new module called module-not-found in the case a Routing cannot be done due to the State Id is not configured or the View / View Models cannot be loaded.
  • The oj-navigation-list now is bind to a Knockout Observable called selectedNavItem exposed in the appController.js
    
    
  • The selectedNavItem is subscribed for changes, so it will trigger the Router go programmatically. So, the Promise rejection can be catch.
    // Handler navigation
          self.selectedNavItem = ko.observable('dashboard');
          self.selectedNavItem.subscribe(function (newValue) {
            self.router.go(newValue).then(function (navStatus) {
              console.log(navStatus.hasChanged);
            }).catch(function (rejection) {
              console.log("Where the fuck is this Router State Id in the Router Configuration?");
              self.router.go('module-not-found');
            })
          });
  • In addition, I modified the code related to loadModule which is responsible of loading the setting up the View and View Model for the oj-module. Here also we make use of the rejection catch if any of the Promises return by Promise.all have failed.
    self.loadModule = function () {
            ko.computed(function () {
              var name = self.router.moduleConfig.name();
              var viewPath = 'views/' + name + '.html';
              var modelPath = 'viewModels/' + name;
              var masterPromise = Promise.all([
                moduleUtils.createView({ 'viewPath': viewPath }),
                moduleUtils.createViewModel({ 'viewModelPath': modelPath })
              ]);
              masterPromise.then(
                function (values) {
                  self.moduleConfig({ 'view': values[0], 'viewModel': values[1] });
                }
              ).catch(function (reason) {
                console.log("Where the fuck are the View and ViewModel attached to this Router State Id?");
                self.router.go('module-not-found');
              })
            });
          };
In the example, the Incidents module have been removed from the Router configuration and the About Module does not has the corresponding View / View Model.

Comments

Post a Comment

Popular posts from this blog

OJET: Inter-Module communication in TypeScript Template

OJET: Build and Deploy in an Application Server

OJET: Select All options using only Checkboxset