composite-js

Composite Binding      ≡ Table of Contents      DataSource


Routing

Seanox composite-js can organize page presentation in views addressed by paths (routes). Routing supports a hierarchical directory structure based on the IDs of nested composites in the markup. It controls visibility and access permission for views through paths, the so-called view flow. Routing uses the DOM to insert and remove views depending on the situation.

+-----------------------------------------------+
|  Page (#)                                     |
|  +-----------------------------------------+  |
|  |  View A (#A)                            |  |
|  |  +-----------------------------------+  |  |
|  |  |  View B (#A#B)                    |  |  |
|  |  |  +-----------------------------+  |  |  |
|  |  |  |  View C (#A#B#C)            |  |  |  |
|  |  |  +-----------------------------+  |  |  |
|  |  +-----------------------------------+  |  |
|  +-----------------------------------------+  |
+-----------------------------------------------+

Contents Overview

Terms

Page

In a single page application, the page is the basic framework and runtime environment of the entire application.

View

A view is a representation of composites or content that may also contain other views and subviews. Views can be static and therefore always shown, or path-controlled with the attribute route. Paths address the complete chain of nested views and show the parent views in addition to the target view.

This behavior requires routing to be enabled by adding the route attribute to the <body> element.

<body route>
  <header id="header" composite>
    always shown, regardless of the path
  </header>
  <main>
    <div id="a" composite route>
      shown with path #a
    </div>
    <div id="b" composite route>
      shown with path #b
    </div>
    <div id="c" composite route>
      shown with path #c  
    </div>
  </main>
  <footer id="footer" composite>
    always shown, regardless of the path
  </footer>
</body>

View Flow

View flow describes the access control and the sequence of views. The routing provides interfaces, events, permission concepts and interceptors with which the view flow can be controlled and influenced.

Navigation is based on paths that use the URL hash. It is triggered by changing the URL hash in the browser, by using hash links and in JavaScript with window.location.hash, window.location.href, Routing.route(path) and Routing.forward(path).

<a href="#a#b#c">Goto root + a + b + c</a>
<a href="##">Back to the parent</a>
<a href="##x">Back to the parent + x</a>

The path syntax is described in chapter Paths.

Routing.route("#a#b#c");
Routing.route("##");
Routing.route("##x");
Routing.forward("#a#b#c");
Routing.forward("##");
Routing.forward("##x");

Unlike the route method, forwarding is executed directly and does not trigger asynchronous forwarding by changing the location hash.

Routing accepts all paths (routes) and covers the destinations from the root. Subsequent path components are treated as path parameters and can be used in the business logic of the views.

Permission Concept

The permission concept is based on permit methods in the application modules. The composer calls the permit method during each (re-)rendering if the application module implements it. These return values are possible:

undefined / no return value

The view is shown if the current path covers the path of the view.

true

The view is shown if any parent views are also shown.

false

The view and possible sub-views are not shown.

string

The return value is a path. The view and possible sub-views are not shown and the page/navigation is redirected to the returned path.

const example = {
    permit() {
        if (condition === 1)
            return;        
        if (condition === 2)
            return true;
        if (condition === 3)
            return "#redirect";
        return false;
    }    
};

#export example;

Interceptors

Interceptors allow custom logic to be executed during navigation before routing checks path validity, resolves the target view and updates the view flow. They are suitable for tasks such as authentication checks, redirects, route migration or custom navigation handling and can influence whether the navigation continues.

An interceptor is registered with Routing.customize(path, actor). The path can be either an exact route string or a regular expression. The actor is a function that is executed when the specified path matches the requested navigation target. The actor is a callback that receives the previous hash and the new hash as parameters.

Routing.customize("#a#b#c", (previousHash, newHash) => {
    console.log("Navigation from", previousHash, "to", newHash);
});

Execution order

Interceptors are executed in the order in which they were registered.

All registered interceptors are checked. If an interceptor matches the requested path, its actor function is executed. Following interceptors receive the potentially modified navigation target.

An interceptor can stop further processing of the current navigation by returning false explicitly.

Routing.customize("#a#b", (oldHash, newHash) => {
    if (!User.isAuthenticated())
        return false;
});

Any other return value does not affect routing.

Path matching

A string interceptor matches the specified path and all nested paths below it.

Routing.customize("#a", actor);

matches:

#a
#a#b
#a#b#c

but not:

#abc
#c#b#a

Regular expressions can be used for pattern-based matching:

Routing.customize(/^#a#\d+$/, actor);

Interceptors do not create entries in the routing history. They are executed within the current navigation event.

An interceptor can modify the target navigation if required. For example, window.location.replace() can be used to replace the current URL without creating an additional browser history entry.

Routing.customize("#old-path", (oldHash, newHash) => {
    window.location.replace("#new-path");
});

Changes made by interceptors directly affect the following path resolution and view rendering.

Paths

Paths are used for navigation, routing and view flow control. The target can be a view or, when using interceptors, a function. For SPAs (Single-Page Applications), the anchor part of the URL is used for navigation and routes.

https://example.local/example/#path

Similar to a file system, absolute and relative paths are supported. Paths consist of case-sensitive words that only use 7-bit ASCII characters above the space character. Characters outside this range are URL encoded. The words are separated by the separator character (#).

#a#b#c#d

Repeated use of the separator (#) allows jumps back in the path to be mapped. The number of repetitions indicates the number of returns in the direction of the root.

#a#b#c#d##x   -> #a#b#c#x
#a#b#c#d###x  -> #a#b#x
#a#b#c#d####x -> #a#x

The navigation with these paths is described in chapter Navigation.

The following path types are supported.

Root Path

These paths are empty or contain only one separator character.

<a href="#">Back to the root</a>

Relative Path

Relative paths are based on the current path and begin with either a word or a sequence of the separator (#) described above.

<a href="##">Back to the parent</a>
<a href="##x">Back to the parent + x</a>
<a href="###">Back to the parent + parent</a>
<a href="###x">Back to the parent + parent + x</a>

Relative paths without separator at the beginning are possible, but only work with Routing.route(path) and Routing.forward(path).

Routing.route("x#y#z");
Routing.forward("x#y#z");

Important
Links with these paths are interpreted by the browser as a reference to another page.

Absolute Path

Absolute paths start with the root, represented by a leading separator character (#). If the path consists of just this separator and nothing else, it is the Root Path.

<a href="#a#b#c">Back to the root + a + b + c</a>

Composite Binding      ≡ Table of Contents      DataSource