hyperHTML: generic content in a loop is always rendered full and lose it's bindings (click events)

429 views Asked by At

I have some problems by using hyperHTML (maybe only some understandings-problems).

When I have dynamic content in a loop, the content is fully rendered and lose it's bindings (like document.body.innerHTML = content, which is not the idea of hyperHTML, isn't it?). Please see my example below:

function render() {
  console.log('render');
  
  hyperHTML.bind(document.body) `start:<br>
    ${[1,2,3].map(item => `
      count <button id="testbutton${item}">button${item}</button><br>
    `)}<br>
    press button2<br>
    <button id="testbutton">Test Button</button><br>
    last rendering ${new Date().toTimeString()}`;
}

function init() {
  render();
  let self = this;
  document.querySelector('#testbutton2').addEventListener('click', () => self.render());  
  document.querySelector('#testbutton').addEventListener('click', () => self.render());  
}
window.addEventListener('load', () => init());
<script src="https://webreflection.github.io/hyperHTML/min.js"></script>

The first time button2 is clicked the content is rendered. The initial binding is still working. After the content is rendered again the listener is lost.

On the other side, the Test Button is not rendered again. The binding is still present.

Could somebody explain me, how to use hypeHTML in a proper way by iterating over a list.

Thanks, Matthias

1

There are 1 answers

2
Andrea Giammarchi On BEST ANSWER

In hyperHTML there are basically two utilities: bind, which renders content inside a node, and wire, which create content instead.

enter image description here

The wire method gives you the ability to relate its content to a specific object, and this is the missing bit of your snippet.

You are indeed simply returning an array of strings, and an Array as interpolation value, as described in the documentation, is an explicit opt-in for html but it's just about dealing with strings, not DOM node.

You are also using that string as regular template literals, and not as hyperHTML content, because you are using interpolations in the wild, like inside attributes, which is not allowed in hyperHTML (read about partial attributes in the documentation).

To solve all these issues at once, you just need to wire either the same item, if that's an object, or a reference that won't change, like the hyperHTML container itself.

Since you want to relate inner content multiple times, all you need to do is to use an :id so that per N items you'll have N weak relationships.

I have created a Code Pen example that shows all this through very few changes to your original code.