Skip to content

Instantly share code, notes, and snippets.

@danigb
Last active November 29, 2019 13:44
Show Gist options
  • Save danigb/67499c6481d72efcdb203ac45ba5d1ae to your computer and use it in GitHub Desktop.
Save danigb/67499c6481d72efcdb203ac45ba5d1ae to your computer and use it in GitHub Desktop.
An utility function to create testable views
/**
* An utility function to create views. Views are objects that abstract the DOM.
*
* It's a very thin layer that will allow to write frontend tests if
* needed and get rid of jQuery
*
* The idea of this function is to reduce boilerplate: instead of creating
* by hand the elements we need with jQuery, we just provide the selectors
* and it returns an object with the same shape.
*
* @param {*} selector - the selector to find inside the given parent
* @param {*} children - an object of childrens
* @return A function that creates a view from a parent
*
* @example
* const LoginForm = viu('form.login', {
* nameField: 'input[type=text]',
* button: 'button',
* })
*
* const form = LoginForm()
* form.nameField.setText('...');
* form.on('submit', () => {})
*/
export function Viu(selector, children) {
if (typeof selector === "function") return selector;
// returns a function that creates the actual Viu tree
return (overrideSelector = undefined, parent = document) => {
// create the main element
const view = createElement(overrideSelector || selector, parent);
// iterate children recursively to build the whole tree
const keys = children ? Object.keys(children) : [];
keys.forEach(key => {
if (view[key]) throw Error(`'${key}' is not a valid children name.`);
view[key] = Viu(children[key])(undefined, view.el);
});
return view;
};
}
function createElement(selector, parent) {
const el = parent.querySelectorAll(selector)[0];
if (!el) throw Error(`Child not found: ${selector} (parent: ${parent.className})`);
return new ViuElement(el);
}
class ViuElement {
constructor(el) {
this.el = el;
}
attr(name, value) {
if (arguments.length === 1) {
return this.el.getAttribute(name);
} else {
this.el.setAttribute(name, value);
}
}
setVisible(isVisible) {
this.el.style.display = isVisible ? "" : "none";
}
setEnabled(isEnabled) {
this.el.disabled = !isEnabled;
}
setText(text) {
this.el.textContent = text;
}
on(event, callback) {
this.el.addEventListener(event, callback);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment