Dynamic Class Bootstrapping
by Simon Harte
HTML
<div class="js-linkComponent" data-newTab>
<span class="js-linkTarget" data-link="link1"></span>
</div>
<div class="js-linkComponent">
<span class="js-linkTarget" data-link="link2"></span>
</div>
<div class="js-linkComponent">
<span class="js-linkTarget" data-link="link3"></span>
</div>
<div class="js-linkComponent" data-newTab>
<span class="js-linkTarget" data-link="link4"></span>
</div>
JavaScript
// Base Component Class
class Component {
static get defaults() {
return {
errors: {
noCtx: 'no context node found',
}
}
}
constructor(context) {
if (!context) {
console.error(`${this.constructor.name}: ${Component.defaults.errors.noCtx}`);
return;
}
this.context = context;
}
collectElements(selectors) {
const elements = {};
for (let [key, selector] of Object.entries(selectors)) {
const nodes = this.selectInContext(selector);
elements[key] = nodes.length > 1 ? nodes : nodes[0];
}
return elements;
}
selectInContext(selector, all = true) {
const method = all ? 'querySelectorAll' : 'querySelector';
return this.context[method](selector);
}
}
// Link Component File
class Link extends Component {
static get defaults() {
return {
...super.defaults,
...{
_ctx: '.js-linkComponent',
selectors: {
link: '.js-linkTarget',
},
},
};
}
constructor(context) {
super(context);
this.elements = this.collectElements(Link.defaults.selectors);
this.settings = {
openNewTab: context.hasAttribute('data-newTab'),
}
}
init() {
this.elements.link.addEventListener('click', this.onClickLink.bind(this));
this.populateElements();
}
onClickLink(ev) {
const url = ev.target.getAttribute('data-link');
this.openLink(url);
}
openLink(url) {
if (this.settings.openNewTab) {
window.open(url);
} else {
window.location = url;
}
}
populateElements() {
const target = this.elements.link;
const text = document.createTextNode(`open ${target.dataset.link} in new tab:...