I want to extend an element by a method, but I've heard it is a bad idea. Therefore I'm wondering if it is possible to make a class so that its instances have all the methods and properties of a regular element in the prototype, but instead of extending all elements in the DOM, the additional methods would only be included in the instances of that class.
Example (that doesn't work; just a concept):
class MyElement {
constructor(element) {
Object.setPrototypeOf(this, element);
}
// Only on elements I declare using this class, not on all HTMLElements
triggerDisplay() {
// This function is an example, all regular HTMLElement properties should work
if (this.style.display === 'none') this.style.display = null;
else this.style.display = 'none';
}
}
What I want to achieve is a way to use OOP with the DOM like this:
// Custom class that inherits from a div element
const myCustomElement = new MyElement(document.getElementById('myDiv'));
// OOP
myCustomElement.triggerDisplay();
Instead of:
// Regular element
const myNotCustomElement = document.getElementById('myDiv');
// Functional programming
triggerDisplay(myNotCustomElement);
All I want is a way to properly use object-oriented programming with the DOM. Am I really bound to functional programming when working with it?
If nothing works, is this good to use this:
HTMLDivElement.pprototype.triggerDisplay = function() {
if (this.style.display === 'none') this.style.display = null;
else this.style.display = 'none';
}
?
If you want to be able to call custom methods on an instance which alters a DOM element, it would probably make the most sense to have the class just save the DOM element as a property of the instance, and then look it up when necessary. For example:
class MyElement {
constructor(element) {
this.element = element;
}
triggerDisplay() {
const { element } = this;
if (element.style.display === 'none') element.style.display = null;
else element.style.display = 'none';
}
}
const myCustomElement = new MyElement(document.getElementById('myDiv'));
myCustomElement.triggerDisplay();
If you need to be able to directly reference element properties without going through the .element
property, you can use prototypal inheritence to set the element as the internal prototype of the instance:
const customProps = {
triggerDisplay: {
value: function() {
const element = Object.getPrototypeOf(this);
if (element.style.display === 'none') element.style.display = null;
else element.style.display = 'none';
}
}
};
const makeCustomElement = (element) => {
return Object.create(element, customProps);
};
const myCustomElement = makeCustomElement(document.getElementById('myDiv'));
myCustomElement.triggerDisplay();
(if you also want to assign to properties directly on the myCustomElement
, then use another Object.create
wrapper so that assignment does not mutate the customProps
object)