Wednesday 10 May 2023

Html Select and Options

I've been doing some web development lately, after a really long time disconnected from that. It's a simple internal application and I've decided to use Vanilla js rather than going through the long and painful process of relearning Angular or learning Vue (React is not an option, I had looked into it time ago and the Hooks thing seemed absolutely ridiculous to me).

Using Vanilla js in a sort of small SPA has given me the feeling of understanding and controlling what I'm doing, something that I did not have with Angular. The thing is that looking into how to populate a select element I've come through something pretty interesting. This answer already shows something interesting. As with any other html element, they create the option elements with document.createElement() and set its different properties, what is interesting is that the HtmlSelectElement provides an add() method to add the options, so we can use it rather than the standard appendChild() method.


let cities = ["Paris", "Vienna", "Xixon"];
let selectElement = document.getElementById("usersSelect");
for (const city of cities) {
	let op = document.createElement("option");
	op.name = city;
	op.value = city:
	selectElement.add(op);
}

What is even more interesting, is that we can create the option element using the Option constructor


let cities = ["Paris", "Vienna", "Xixon"];
let selectElement = document.getElementById("usersSelect");
for (const city of cities) {
	selectElement.add(new Option(city, city));
}

I've been using document.createElement for centuries, and then at some point in time, thanks to the MDN documentation I found out that each of the different html elements corresponds with a class inheriting from HTMLElement. So we have HTMLDivElement, HTMLSelectElement, HTMLOptionElement, etc, etc. So, first, for creating an option, why do we use an Option constructor rather than HTMLOptionElement?, and second, why don't we create other html elements invoking HTMLDivElement, etc, rather than document.createElement?

Well, if we try to invoke a new HTMLOptionElement() (or any other new HTMLxxxElement()) we get an error: Uncaught TypeError: Illegal constructor. If we look into the MDN documentation, each HTMLxxxElement is described as an interface. This seems odd, given that in JavaScript there's not syntax for defining interfaces, so in the end it seems like an "interface" is a class which constructor throws an error when being invoked (so it's not directly instantiable). Though we can not directly invoke the HTMLxxxElement constructor, the constructor property of objects created with document.createElement() will point to the corresponding function, and of course instanceof will work fine. I mean:


let d1 = document.createElement("div");
d1.constructor.name
"HTMLDivElement" 

d1.constructor === HTMLDivElement
true

d1 instance of HTMLDivElement
true

Creating and option either with new Option() or document.createElement("option") has exactly the same effect. The instanceof operator applied to objects created that way returns true both for Option and for HTMLOptionElement, but in both cases the instances constructor property points to the HTMLOptionElement function, not to the Option function. So the Option function is considered a constructor, but a particular one. It can be invoked with new (in JavaScript any 'non arrow function' can be invoked with new and returns an object in such case) and has been designed to initialize the object that it returns, but that object is not an instance of Option, but an instance of HtmlOptionElement.


let op1 = new Option("k", "v");
undefined
op1 instanceof Option;
true
op1 instanceof HTMLOptionElement;
true
op1.constructor === Option
false
op1.constructor === HTMLOptionElement
true

let op2 = document.createElement("option");
undefined
op2 instanceof Option
true
op2 instanceof HTMLOptionElement
true
op2.constructor === Option
false
op2.constructor === HTMLOptionElement 
true

No comments:

Post a Comment