v1.1

App

class App extends Router → App.js

Instance

To start the app create an object instance.
const app = new App(appName);

Properties

The app instance properties are:
Property Description Type Default
$appName The application name. It defines the window property. For example if $appName='myApp' then window.myApp string dodoApp
$debugOpts Debugger options. Set specific option to true if you want to see the debugging messages. See all options. object {...}
$postflight array of postflight functions, will be executed on every route after the controller's __postrend() Function[] []
$preflight array of preflight functions, will be executed on every route before the controller's __loader() Function[] []
ctrlConstants A controller constants which will not be deleted when one controller is replaced by another controller (when route is changed).
{$appName, $fridge, $httpClient, $auth, $debugOpts, $destroyflight, $model, $modeler, $dd}
object {...}
ctrls A collection of all controllers. This makes possible to use a controller's methods inside another controller. object {}
routeDefs route definitions object[]

Methods

fridge($fridge) :App

Establish a $fridge property that remains accessible and unchanged across all controllers.
The $fridge object will persist even when the app route changes and controllers are replaced. Conversely, other controller properties will be deleted.
This approach is useful for defining values that need to be shared among all controllers.
The $fridge can contain properties and functions.
    ARGUMENTS:
  • $fridge :object - $fridge object, for example {'api_url': 'http://dex8.com'} then the frozen constant will be this.$fridge.api_url and it can be used in every controller
EXAMPLE:
Let's define a constant that will be needed in all or most of the controllers, such as an API URL.
const app = new App('myApp');
const $fridge = {
 api_baseurl: 'http://api.example.com',
 func: (key) => {
   const ctrl = corelib.navig.current.ctrl; // current controller
   const skript = ctrl.skripts[key];
   return ctrl.$model.loggedUser.username !== skript?.user_id.username ? { color: 'green' } : {};
}
}
app.fridge($fridge); // put the object in the fridge
Now we can fetch the api_baseurl in every controller with this.$fridge.api_baseurl

httpClient($httpClient) :App

Set the $httpClient property in all controllers. It can be called with this.$httpClient in the controller.
The HTTP client is used for specific API calls.
    ARGUMENTS:
  • $httpClient :object - the http client object
EXAMPLE:
An app needs HTTP client in the controllers to fetch the JSON from API.

// src/const/$httpClient.js
=========================
import { corelib } from '@mikosoft/dodo';

// default HTTP client
const opts = {
  encodeURI: true,
  timeout: 21000,
  responseType: '', // 'blob' for file download (https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType)
  retry: 0,
  retryDelay: 1300,
  maxRedirects: 0,
  headers: {}
};
const $httpClient = new corelib.HTTPClient(opts);

export { $httpClient };


// src/app.js
=========================
import { $httpClient } from './conf/httpClient.js';
const app = new App('myApp');
app.httpClient($httpClient);
Now this.$httpClient is injected in every controller and can be used to call the API.
// src/controllers/SomeCtrl.js
=============================
import { Controller } from '@mikosoft/dodo';

class SomeCtrl extends Controller {
  async __init() {
    const answer = await this.$httpClient.askJSON('https://jsonplaceholder.typicode.com/posts/1');
  }
}

auth($auth) :App

Inject the auth library into all controllers and access it using this.$auth within the controller.
This is particularly useful for applications that require authentication guards on all routes, such as web panels where users need to log in.
    ARGUMENTS:
  • $auth :object - instance of the Auth class
EXAMPLE:
Create an app which has login and dashboard page. After successful login the user is redirected to dashboard.
Study the Stackblitz example

debug($debugOpts) :App

Set the debug options.
EXAMPLE:
import { $httpClient, $debugOpts } from './conf/index.js';
const app = new App('myApp');
app
  .httpClient($httpClient)
  .debug($debugOpts);

preflight($preflight) :App

Define preflight functions which will be executed on every route before controller __loader() hook.
    ARGUMENTS:
  • $preflight :Function[] - array of functions (some or all functions can be async, with trx argument)
EXAMPLE:
Define and export preflight functions in the lib/$preflight.js
// lib/$preflight.js
const rend_loggedUser = (trx) => {
  const ctrl = corelib.navig.current.ctrl; // fetch current page controller from navig
  ctrl.$model.loggedUser = ctrl.$auth.loggedUser; // update loggedUser in the views/inc/.../header.html
};
export default [rend_loggedUser];


// app.js
const app = new App('webPanel');
app
  .auth(auth)
  .fridge('wsLib', wsLib)
  .preflight($preflight)
  .postflight($postflight)
  .debug($debugOpts);

postflight($postflight) :App

Define postflight functions which will be executed on every route after controller __postrend() hook.
    ARGUMENTS:
  • $postflight :Function[] - array of functions (some or all functions can be async, with trx argument)

ssr() :App

Enable Server-Side Rendering (SSR) mode. When called, the app sets an internal $ssr flag which causes a ssr-ready event to be dispatched on the window object once the initial route has been fully rendered.
This is useful for pre-rendering tools and crawlers that need to know when the first page render is complete.
    ARGUMENTS:
  • - no arguments
EXAMPLE:
Enable SSR mode so the server-side renderer knows when the initial view is ready.
const app = new App('myApp');
app
  .httpClient($httpClient)
  .ssr()            // enable SSR mode — dispatches 'ssr-ready' event after first route render
  .routes($routes)
  .listen();

// in the SSR / prerender environment listen for 'ssr-ready':
window.addEventListener('ssr-ready', () => {
  // page is fully rendered — safe to take a snapshot
});

destroyflight($destroyflight) :App

Define destroyflight function which will be executed when controller is destroyed i.e. when route is changed.
It's useful for example when you want to off() some event listeners.
    ARGUMENTS:
  • $destroyflight :Function - a single function (This function doesn't have arguments)

i18n($i18n) :App

Set the global window.<appName>.i18n property, which is used in the View.loadI18n(langCode) method.
The language object $i18n can be loaded from various sources such as databases, files, browser storage, etc.
It is not saved in the controller object to keep it as small as possible. The language $i18n object can be large and significantly increase the size of the controller object.
    ARGUMENTS:
  • $i18n :object - object with language translations, for example {de: {common: {USERNAME: 'Nutzername'}, home: {TITLE: 'Startseite', LOGIN: 'Anmeldung'}}}
EXAMPLE:
As the i18n() is async function it must be wrapped in async function so await can be used. Call i18n() before routes() and listen() because language json files must be read before controller execution.
const initApp = async () => {
  const app = new App('dodoApp');
  app
    .auth($auth)
    .httpClient($httpClient)
    .debug($debugOpts)
    .i18n($i18n); // load language JSON files in the window.dodoApp.i18n
    .routes($routes)
    .listen();

routes($routes) :object

Define app routes i.e. which controller will be executed when app URL is changed.
    ARGUMENTS:
  • $routes :Array[] - the routes array. Each entry is an array: ['when' | 'notfound' | 'do' | 'redirect', ...]
EXAMPLE:
Create HomeCtrl controller and inject it in the $routes.
const $routes = [
  ['when', '/', HomeCtrl],
  ['when', '/user/:id', UserCtrl, { authGuards: ['isLogged'] }],
  ['notfound', NotFoundCtrl],
  ['do', [f1, f2]],
  ['redirect', '/old', '/new']
];

app.routes($routes).listen();

listen() :void

Listen for the route changes. Should be used after routes() method.
    ARGUMENTS:
  • - no arguments

Stackblitz Examples

  • Example 1 - how to make APP instance and how to use its methods