# Navigation for __Single Page Applications__

[![+Professional Support](https://www.totaljs.com/img/badge-support.svg)](https://www.totaljs.com/support/) [![+Chat with contributors](https://www.totaljs.com/img/badge-chat.svg)](https://messenger.totaljs.com)

Navigation uses [__jRouting library__](https://github.com/totaljs/jRouting), this library is designed for creating __Single Page Applications__. jComponent navigation uses two aliases to navigation:

- `NAV` or `NAVIGATION` defined in `window` scope
- [Source-code on GitHub](https://github.com/totaljs/jRouting)

__Quick navigation__:

- [Properties](#properties)
- [Methods](#properties)
- [Events](#events)
- [Routing](#routing)
- [Middleware](#middleware)
- [Good to know](#good-to-know)

## Properties

```javascript
// +v16 Enables hashtags instead of HTML 5 History API
// default: false
// returns {Boolean}
NAV.hashtags;

// Contains the current URL address
// IMPORTANT: a path can be used in jComponent
// returns {String}
NAV.url;

// +v16 Is back button enabled?
// returns a count of page numbers for "back" button
// IMPORTANT: a path can be used in jComponent
// returns {Number}
NAV.isback;

// +v16 Is forward button enabled?
// returns a count of page numbers for "forward" button
// IMPORTANT: a path can be used in jComponent
// returns {Number}
NAV.isforward;

// +v17 Contains "params" data parsed according to the URL
// IMPORTANT: a path can be used in jComponent
// returns {Object}
NAV.params;

// +v17 Contains a repository data for each URL
// IMPORTANT: a path can be used in jComponent
// returns {Object}
NAV.repository;

// +v17 Contains parsed query arguments according to the URL
// IMPORTANT: a path can be used in jComponent
// returns {Object}
NAV.query;
```

## Methods

- [`MIDDLEWARE(name, fn)`](#)
- [`NAV.autosave()`](#)
- [`NAV.back()`](#)
- [`NAV.clientside(selector)`](#)
- [`NAV.forward()`](#)
- [`NAV.load([expiration])`](#)
- [`NAV.refresh()`](#)
- [`NAV.remove(url)`](#)
- [`NAV.save()`](#)
- [`REDIRECT(url)`](#)
- [`ROUTE(url, action, [middleware])`](#)

#### `MIDDLEWARE()`

Method registers a new middleware for routing. Middleware are async methods which can stop route execution while all middlewares aren't done. [Look on example with Middleware](#middleware).

```javascript
MIDDLEWARE(name, fn);
// @name {String} A middleware name
// @fn {Function(next)} Executor
// returns {NAV}

MIDDLEWARE('delay', function(next, options, roles) {
	// @next {Function} "next(false)" or "next(Error") won't be continue in processing
	// @options {Object} custom options defined in a route
	// @roles {String Array} roles defined in a route
	setTimeout(next, 1000);
});
```

`+v15` __supports middleware execution__ outside of routes:

```javascript
MIDDLEWARE(['delay', 'users'], function() {
	// all middlewares are done
});
```

#### `NAV.autosave()`

`+v16` This method performs saving of history into the `localStorage`. It can be executed onetime when the application is starting.

```javascript
NAV.autosave();
```

#### `NAV.back()`

Method performs browser `back` operation.

```javascript
NAV.back();
// returns {NAV}
```

#### `NAV.clientside()`

Method watchs all links on the selector path. If the user click on the link then the method performs internal `REDIRECT()` - browser doesn't perform a classic redirect to server-side. This method will watch all links and the links can be created dynamically.

```javascript
NAV.clientside(selector);
// @selector {String} jQuery selector
// returns {NAV}

NAV.clientside('a.routing');
```

#### `NAV.forward()`

`+v16` Method performs browser `forward` operation.

```javascript
NAV.forward();
// returns {NAV}
```

#### `NAV.load([expiration])`

`+v16` This method loads a history from the `localStorage`. It can be executed onetime when the application is starting.

```javascript
NAV.load([expiration]);
// @expiration {String} optional, can contain an expiration for the history

NAV.load('1 hour'); // loads a history if the history wasn't saved more than 1 hour
// or
NAV.load(); // loads a history
```


#### `NAV.refresh()`

Method performs `refresh`.

```javascript
NAV.refresh();
// returns {NAV}
```

#### `NAV.remove()`

Method removes registered routing.

```javascript
NAV.remove(url);
// @url {String}
// returns {NAV}

NAV.remove('/');
```

#### `NAV.save()`

`+v16` This method saves a history into the `localStorage`. `NAV.autosave()` executes this method automatically if the history was modified.

```javascript
NAV.save();
```

#### `REDIRECT()`

Method performs redirect without calling backend.

```javascript
REDIRECT(url, [model]);
// @url {String} relative URL address
// @model {Object} custom model for this route

REDIRECT('/users/');
```

#### `ROUTE()`

Method registers a new route. More info in Routing section bellow.

```javascript
ROUTE(url, fn, [middleware], [init]);
// @url {String} relative URL address
// @fn {Function} executor
// @middleware {String Array} optional, can contain middleware + roles + options
// @init {Function} optional, init function is executed only the one time

ROUTE('/', function() {
	// action
}, ['middlewareA', 'middlewareB', '@role1', '@role2']);
```

## Events

Global navigation events.

```javascript
ON('location', function(url) {
	// URL address has been changed
});

ON('404', function(err) {
	// Route not found.
});

ON('500', function(err) {
	// Internal client-side error
});
```

## Routing

Routing can be defined everywhere, but I recommend to create it in some client-side file like `routes.js` for clarity.

```javascript
ROUTE('/', function() {
	// this action is executed if the URL will be "/"
});

ROUTE('/users/', function() {
	// this action is executed if the URL will be "/users/"
});

ROUTE('/products/{category}/', function(category) {
	// this action is executed if the URL will be "/products/SOMETHING/"
	console.log(category);
});
```

## Middleware

Middleware can affect routing's action before is executed. So you can perform authorization or another operations in middleware, for example:

```javascript
MIDDLEWARE('authorize', function(next, options, roles) {

	if (window.user)
		return next();

	// ...
	// sign-in
	window.user = user;
	next();
	
});
```

__Custom options + roles in middleware__:

```javascript
ROUTE('/', function() {
	
	// some action
	
}, ['middleware', { name: 'Custom options' }, '@admin']);

MIDDLEWARE('middleware', function(next, options, roles) {

	console.log(options);
	// Output: { name: 'Custom options' }

	console.log(roles);
	// Output: admin

	next();
});
```

__Custom errors in middleware__:

```javascript
MIDDLEWARE('error', function(next, options, roles) {

	if (someError) {    
		next(false); // or next(ErrorInstance)
		REDIRECT('/fallback/'); // or do something
		return;
	}

	next();
	
});
```

## Good to know

### How to read a value from URL address?

```javascript
var query = READPARAMS();
// or
// var query = READPARAMS('q=Peter&age=30');

// ?q=Peter
console.log(query.q);
// Output: Peter

// ?age=30
console.log(query.age);
// Output: 30
```