Regulator is a tiny, opinionless tool for structuring your Javascript applications. We use it internally at AngelList. It aims to keep you sane at any application scale.
Regulator weighs about 1.2KB (compressed). It requires a Promises/A+ implementation.
It also optionally makes use of MutationObserver
for reacting to changes in the DOM.
$ bower install regulator
The world is filled with excellent Javascript frameworks, many of them full-featured and highly structured. Regulator is extremely minimal, simply managing structured initialization of your components and allowing them to communicate with each other. Perfect for loosely coupled applications at any scale, using any toolkit.
-
Automatic, tightly scoped initialization
Associate HTML elements directly with their Javascript behaviors, regardless of when or where they were added to the DOM. Automatically run initialization on server- and client-rendered content, without the need for context-specific setup.
-
Clean communication between components
Expose controllers for the logical pieces of your interface, and easily give them access to one another. Controllers can be built asynchronously, and can be anything from plain objects to Backbone views to Ember controllers.
Denote components on your page with data-rc
, and give them a name that describes how to initialize them:
<button data-rc="alert">Click me</button>
Create a Regulator
instance and tell it how to initialize your components:
var myRegulator = new Regulator(function(name, el) {
return require('initializers/' + name)(el);
}).observe();
// initializers/alert.js
module.exports = function(el) {
var triggerAlert = function() { alert('clicked!') };
el.onclick = triggerAlert;
return { triggerAlert: triggerAlert }
};
Now whenever you add an element with data-rc="alert"
to the DOM, a click listener will be bound:
var content = $.get(someUrl); // Contains an "alert" block
$('body').append(content); // "alert" block is initialized automatically
You can access the return value of the initialization function through your Regulator
instance:
myRegulator.withController($("[data-rc='alert']"), function(controller) {
controller.triggerAlert();
});
var myRegulator = new Regulator(strategy, options = {})
strategy
is a function which takes (name, el)
, where name
is the name of a component
and el
is its root element. The return value of this function is referred to as the element's controller.
Available options are:
attribute
: The HTML attribute which denotes a component. Default:'data-rc'
throttle
: When observing with aMutationObserver
, the maximum frequency (in milliseconds) to call#scan()
. Default:200
poll
: When observing in the absence of aMutationObserver
, the interval to poll the DOM for changes. Set tofalse
to disable the polling fallback. Default:1000
root
: Only components within this element will be initialized. Default:window.document.body
Promise
: The Promises/A+ implementation to use. Default:window.Promise
MutationObserver
: The MutationObserver implementation to use. Default:window.MutationObserver
Depending on your use case, you can initialize your components in one of three ways:
myRegulator.initialize(element)
Synchronously invokes the initializer for a single component. If called repeatedly, only invokes the initializer once.
Returns a Promise
resolving to the element's controller.
myRegulator.scan()
Synchronously finds and initializes all components which haven't been initialized yet. Returns a promise that resolves when all initializations are complete.
myRegulator.observe()
Observes the page for changes, and initializes new components as they're added. If MutationObserver
is present,
uses it for relatively performant initialization; otherwise, falls back to #scan
running repeatedly at the interval
specified by the poll
option.
Regulator is optimized for fast detection of relevant changes to the DOM, but you should be aware of the performance
implications of MutationObserver
or polling when using this option. You should also be aware that initialization
will occur asynchronously, at some point after elements have been added to the page. If you need finer-grained
control, use #scan
or #initialize
.
myRegulator.withController(iterable, callback)
Invokes callback
with the controller for each component root in iterable
(iterable
can also be a single element).
Also initializes the components if they haven't been already.
Controllers can also be accessed through the return value of #initialize
:
myRegulator.initialize(el).then(function(controller) {
// ...
});
Run tests using karma:
$ npm install
$ node_modules/bin/karma start