vvidget is an abstraction for creating uniform JavaScript plugins.
It creates plugins that take care of a few problems:
- Use a single naming-and-selector convention for defining all widgets
- Helps avoid lots of random selectors sprinkled through the code
- You always know which DOM elements are carrying one of these widgets
- Reliably binding to ready and page-refresh events, to initialize ajax-loaded elements once and only once.
- Helps manage PJAX reloads and HTML fragment injection
- Nested widgets can be easily and safely activated
- Loading options from data attributes.
- Namespaces keep collisions from occurring, so a single DOM element can safely be host to multiple widgets
Create an instance of the plugin builder with your preferred configuration:
import widgetSetup from 'widget';
const widget = widgetSetup({ attr: 'ue', data: 'ue-widget' }, 'page-refreshed', 'fragment-refreshed');
// DOM elements with selector of `ue`, or `data-ue-widget` will activate widgets created with this
// config
This configuration let's us describe widgets and pass options in data attributes:
<div class='simple-widget'
data-ue-widget='widget-name'
data-widget-name-option-one='option1'
data-widget-name-option-two='option2'>
This will be mapped to the plugin we create with the matching name:
widget('widget-name', function(opts, ready) {
$el = this;
ready(() => {
// teardown
});
}, {
defaults: {},
init: 'nextTick'
});
You may attach multiple widgets to the same DOM element by separating the widget names with a space character.
Example:
<div data-ue-widget='widget-1 widget-2'></div>
This is equivalent to:
<div ue='widget-1 widget-2'></div>
There is a legacy event-driven mode, that requires triggering events to initialize widgets. This is useful for PJAX and other page-refreshing systems.
widget('remote-resource', function(opts, ready) {
fetch('/example').then((htmlFragment) => {
this.append(htmlFragment);
this.trigger('fragment-refreshed');
// any widgets nested within the HTML fragment will be activated
});
this.addEventListener('click', fetchData);
ready(() => {
this.removeEventListener('click', fetchData);
});
})
Instead of manually triggering events, you can also choose to opt into using a MutationObserver to detect when new elements are added to the DOM.
import widgetSetup from 'widget';
const widget = widgetSetup({ attr: 'ue', data: 'ue-widget' }, 'page-refreshed', 'fragment-refreshed');
widget.stopWatchingEvents();
widget.startWatchingDOM();