1

Imagine a function whose signature looks like:

function readElement(element: HTMLElement): string;

To implement the function you will have to check if the element is using the value property (i.e. HTMLInputElement) or the textContent property (i.e. SpanElement) and get the respective property. What I am asking is a couple of ways that can implement readElement, are foolproof and have high browser compatibility.

Here is a list of ways I've used to tackle the problem in the past:

  • element.value !== undefined
  • element.constructor.hasOwnProperty("value")
  • typeof element.value === "string"
  • [HTMLInputElement, HTMLTextAreaElement,...].some(proto => element instanceof proto)
nick zoum
  • 7,216
  • 7
  • 36
  • 80
  • 1
    `if ("value" in someElement) ...` – Pointy Mar 08 '19 at 14:09
  • 1
    @AndréDS That will fail on ``. – connexo Mar 08 '19 at 14:14
  • 2
    @AndréDS — That's the point. `if(element.value)` will report *false* if it does have a value property that has a value which is an empty string. – Quentin Mar 08 '19 at 14:20
  • Oh yes my bad @Quentin. I delete – André DS Mar 08 '19 at 14:23
  • Just a note, reading at the element level is a very bad idea for this function, go as deep as node level. – Kaiido Mar 09 '19 at 13:26
  • @Kaiido Well the aim of this is to change the text of an element, so i doubt that will be a problem – nick zoum Mar 09 '19 at 17:00
  • And what if your element is a div with some text nodes and an input and a script or other non visible elements inside itself? [Here](https://stackoverflow.com/a/46230366/3702797) is a more complete solution, while probably still not perfect. – Kaiido Mar 09 '19 at 23:15
  • @Kaiido Good point, didn't think that far. Though I've never had text-nodes and elements in the same element. – nick zoum Mar 10 '19 at 13:10

1 Answers1

3

To test if an object has a property, simply use 'prop' in obj:

[...document.body.querySelectorAll('*')].forEach((el)=> {
  console.log(el.tagName + ' contains: ' + readEl(el));
})

function readEl(el) {
  return 'value' in el ? el.value : el.textContent || false;
}
<p>para</p>
<input value="input" />
<textarea>textarea</textarea>
<div>div</div>
connexo
  • 53,704
  • 14
  • 91
  • 128
  • Thanks, forgot that it will read the full prototype chain unlike `hasOwnProprty` – nick zoum Mar 08 '19 at 14:22
  • Which is why `hasOwnProperty`exists in the first place. **Own** – connexo Mar 08 '19 at 14:22
  • While this is a way i didn't think of I was hoping there also a way that doesn't involve checking for the value like `[HTMLInputElement, HTMLTextAreaElement,...].some(proto => element instanceof proto)` but without having to write every single element that has a value property – nick zoum Mar 08 '19 at 14:37
  • Sorry, I don't get what you're saying. What exactly about the suggested Method does not suite your needs? – connexo Mar 08 '19 at 14:40
  • Well if elements like `HTMLInputElement` and `HTMLTextAreaElement` implemented the same prototype rather than just directly implementing `HTMLElement` then we could had been able to do `element instanceof AbstractHTMLElementWithValue` – nick zoum Mar 08 '19 at 14:44