Search code examples
javascripthyperhtml

Access DOM when using hyper.Component


When using HyperHTMLElement it's possible to access the contents of the component by simply using this.children or this.querySelector(), since it's an element.

But how would I achieve similar behavior when using hyper.Component?

The hypothetical example I have in mind is from React docs: https://facebook.github.io/react/docs/refs-and-the-dom.html - I'd like to focus a specific node inside my DOM.

I have a codepen sandbox where I'm trying to solve this: https://codepen.io/asapach/pen/oGvdBd?editors=0010

The idea is that render() returns the same Node every time, so I could save it before returning and access it later as this.node:

render() {
  this.node = this.html`
    <div>
      <input type="text" />
      <input type="button" value="Focus the text input" onclick=${this} />
    </div>
  `;
  return this.node;
}

But that doesn't look clean to me. Is there a better way to do this?


Solution

  • The handleEvent pattern is there to help you. The idea behind that pattern is that you never need to retain DOM references when the behavior is event-driven, 'cause you can always retrieve nodes via event.currentTarget, always pointing at the element that had the listener attached, or event.target, suitable for clicks happened in other places too within a generic click handler attached to the wrap element, in your demo case the div one.

    If you'd like to use these information, you can enrich your components using an attribute to recognize them, like a data-is="custom-text-input" on the root element could be, and reach it to do any other thing you need.

    onclick(e) {
      var node = e.target.closest('[data-is=custom-text-input]');
      node.querySelector('[type=text]').focus();
    }
    

    You can see a working example in a fork of your code pen: https://codepen.io/WebReflection/pen/RLNyjy?editors=0010

    As alternative, you could render your component and address its content once as shown in this other fork: https://codepen.io/WebReflection/pen/LzEmgO?editors=0010

      constructor() {
        super().node = this.render();  
      }
    

    at the end of the day, if you are not using custom elements but just basic, good'ol DOM nodes, you can initialize / render them whenever you want, you don't need to wait for any upgrade mechanism.

    What is both nice and hopefully secure here, is that there's no way, unless you explicitly expose it, to address/change/mutate the instance related to the DOM element.

    I hope these possibilities answered your question.