# Notify (toast notifications) Links: [Home](../index.md) A notification manager: one fixed container in a corner (or edge) of the screen where `log()`, `info()`, `warn()`, `error()` and `debug()` rows appear with a scale-in transition, auto-expire after a per-type delay and go away on click. Each row is an `ApplicationPrototype` with `message()`, `data()`, `expire()` and `remove()`. Written by SGApps.IO. ## Loading the Module ```js Application.require("elements/notify").then(function (NotifyManager) { var notify = NotifyManager(); // one manager = one container document.body.appendChild(notify.node()); // nothing is attached for you notify.position('top', 'right'); notify.info('Build finished', '12 files, 0 warnings'); }); ``` **Dependencies:** `extensions/prototype`, `elements/popup` (for the `alert` / `confirm` / `prompt` / `popup` shortcuts), `uri-load`. The module links `elements/notify/style.css` (855 lines: the container positions, the row transitions, the arrow per type) when it loads. The `animated` classes it sets on rows come from the RegalRoyal theme / animate.css and are optional. For several containers at once use [Notify Service](notify-service.md). ## Markup ```html
notify.node() -- position: fixed, z-index 3000000000
one per notification, newest first
Build finished
12 files, 0 warnings
hidden when empty
``` Rows are inserted at the **top** of the container; a row starts with the class `inactive` (scaled to 5 %) and gets `active` (scale 1, 0.5 s transition) 500 ms later; `remove()` drops `active` and detaches the node 500 ms after that. Colours per type: `log` dark grey, `info` blue (`#4C7AA9`), `warn` yellow, `error` crimson, `debug` grey (`#5d5d5d`). ## API ### `NotifyManager()` Returns the **manager**, an `ApplicationPrototype`. | Method | Returns | Description | |---|---|---| | `node()` | `HTMLElement` | The container `
`; append it to `document.body` yourself | | `position(...)` | `true` | Where the container sits. String arguments among `'top'`, `'bottom'`, `'left'`, `'right'`, `'center'`; a later argument replaces its opposite (`'top'` drops `'bottom'`); a single `'left'` / `'right'` gets `'center'` added. The sorted list becomes the `m_notify-position` attribute. Object arguments are applied as inline styles to the container (`{ bottom: '60px' }`). Each call starts from an empty list: `position('top')` is `"top"`, not `"top right"` | | `timer(ms)` | number | A global expiry that replaces the per-type delays for rows added afterwards (`0`, the default, keeps the per-type values). Getter without an argument | | `log(message, ...details)` | row | Adds a `log` row (expires after 3.5 s) | | `info(message, ...details)` | row | `info` row, 5 s | | `warn(message, ...details)` | row | `warn` row, 5 s | | `error(message, ...details)` | row | `error` row, 15 s; `Error` instances among the arguments are rendered as `name: message` | | `debug(message, ...details)` | row | `debug` row, **never expires** (no default delay for this type) | | `add(type, data, [onClick], [vars], [expire])` | row | The general form, see below | | `remove(id)` | -- | Removes the row with that DOM id (`active` class dropped, node detached after 500 ms) | | `alert(...)`, `confirm(...)`, `prompt(...)`, `popup(...)` | popup | Forwarded to the [Popup](popup.md) module with the same arguments | Every method is bound with the default lifecycle configuration, so `notify.on('beforeAdd', fn)` (return `false` to veto), `'onAdd'`, `'afterAdd'` and the same for the other methods are available. Supported positions (the stylesheet has rules for exactly these): `top`, `bottom`, `top left`, `top right`, `bottom left`, `bottom right`, `top center`, `bottom center`, `center left` (from `position('left')`), `center right` (from `position('right')`). The default is `bottom right`. ### `notify.add(type, data, [onClick], [vars], [expire])` | Parameter | Type | Description | |---|---|---| | `type` | string | `'log'` (default), `'info'`, `'warn'`, `'error'`, `'debug'` -- becomes the class `m_notify-type--` and the `m_notify-type` attribute | | `data` | string, array, `arguments`, `Error` | The first item is the **message**, the rest are **detail lines** (each rendered as a `
` in `.m_notify-data`; strings are inserted as HTML, nodes appended). A string is a message alone; an `Error` becomes `"Error: "` plus its stack | | `onClick` | `function (id, vars, event, manager)`, `false` | Called with `this` = the row when it is clicked. Default (omitted): the click removes the row. `false`: the row gets the class `noclick` (`pointer-events: none`) and cannot be clicked at all | | `vars` | object | Stored on the row, returned by `row.vars()` and passed to `onClick` | | `expire` | number, `false`, undefined | Auto-removal delay in ms. Omitted: the per-type default (`log` 3500, `warn` 5000, `error` 15000, `info` 5000, `debug` none), or `timer()` when set. `false`: sticky. A number: that delay, with a **minimum of 510 ms** (`0` therefore removes the row after half a second, not never) | Returns the **row**, an `ApplicationPrototype`: | Method | Returns | Description | |---|---|---| | `message([value])` | row or current message | Setter with a string (HTML) or a node; getter without an argument | | `data([array])` | row or current details | Replaces the detail lines (strings as HTML, nodes appended); getter without an argument | | `expire([value])` | row or current delay | `true` re-arms the per-type default, a number sets a new delay (from now), `false` cancels the timer and makes the row sticky | | `remove()` | -- | Removes the row (through `manager.remove(id)`) | | `vars()` | object | The `vars` object given to `add()` | | `attachToNode(node)` | -- | Moves the row's element into `node.parentElement` (note: the *parent* of the node you pass); `attachToNode(null)` moves it next to the container. Only while the row is attached | | `emit('event:click', [event])` | -- | The click event of the row; listen with `row.on('event:click', fn)` | ## Use Cases ### A progress notification that updates itself ```js Application.require("elements/notify").then(function (NotifyManager) { var notify = NotifyManager(); document.body.appendChild(notify.node()); notify.position('bottom', 'left'); var row = notify.add('info', ['Uploading ...', '0 %'], false, {}, false); // not clickable, sticky upload.on('progress', function (percent) { row.data([percent + ' %']); }); upload.on('done', function () { row.message('Upload complete'); row.data([]); row.expire(3000); // now goes away in 3 s }); }); ``` ### An action on click, with data carried in `vars` ```js notify.add('warn', ['New version available', 'v2.4.0 -- click to reload'], function (id, vars, ev, manager) { location.href = vars.url; }, { url: '/?v=2.4.0' }, false); ``` ### Reporting errors of a request ```js Application.require(["notify :: elements/notify", "request"]).then(function (libs) { var notify = libs.notify(); document.body.appendChild(notify.node()); libs.request().url('/api/save').response('json').then(function (data) { notify.log('Saved'); }, function (err) { notify.error(err); // an Error instance is shown as "Error: " (no stack) // notify.add('error', err); // the add() form renders the Error with its stack as a detail line }); }); ``` ### Global expiry and a custom offset ```js notify.timer(8000); // every new row lives 8 s (log, info, warn and error alike) notify.position('top', 'right', { top: '60px' }); // below a fixed toolbar ``` ## Notes - One manager, one container: to show rows in several places at once use [Notify Service](notify-service.md), which builds ten managers. - Rows are prepended: the newest notification is always the first child of the container, i.e. the one nearest the top of the stack in every layout (the container is anchored to its edge with `position: fixed`, the rows flow downwards from it). - Strings in `message()` / `data()` are inserted as **HTML** -- escape user input. - `remove(id)` and `row.remove()` wait 500 ms for the transition before detaching the node; a row removed twice is harmless. - Live demo: [playground](playground.html#module=notify ':ignore :target=_blank').