biotope / biotope-element

A web component
https://element.biotope.sh
15 stars 5 forks source link

v4 Form Input gets reset on rerender in partial #254

Closed jurekbarth closed 4 years ago

jurekbarth commented 4 years ago

Steps to reproduce the behavior: A little bit hard to explain, that why i also made an example: https://codepen.io/jurekbarth/pen/gOOyWZM

If you fill out every form element and then click the counter. The last form element gets reset because it's not wired to the element. Lighterhtml mentions that in the documentation:

the wired content is not strongly referenced as it is for hyperHTML.wire(ref[, type:id]) unless you explicitly ask for it via html.for(ref[, id]) or svg.for(ref[, id]), where in both cases, the id doesn't need any colon to be unique. This creates content hard wired whenever it's needed.

Expected behavior The form element keeps it's value.

In order to do so you could use html.for() as mentioned in the lighterhtml documentation, e.g.

  renderPartial() {
    return html.for(this)`
        <p>partial</p>
        <input ref=${this.refs.input} type="text" />
      `;
  }

I think it's expected behavior, but it should be mentioned somehow in the docs and the upgrade guide. As far as i know it's not mentioned anywhere.

This only applies to form elements as far as i can think of. It might affect css animations though. So i might need a little more investigation work to get all cases together.

tiagomapmarques commented 4 years ago

I don't know if we should classify this as a bug or as just missing documentation.

In your example if you don't remove the span on L32, then the input is not re-rendered. Suggested replacement:

// here, i'm just replacing the span element with a div element, not removing it the entire element.
${counter % 2 === 0 ? html`<span>${counter}</span>` : html`<div>${counter}</div>`}

This is most likely due to the "diff" algorithm not being able to track the "input" element since a previous element "disappeared". This does seem a reasonable explanation because if you move your L34 to before L32, then the input does not get re-rendered. Additionally, if you don't do it in a partial, everything works as expected.

My suggestion is add some documentation suggesting that developers do not alter the HTML structure of the initial this.html call and use CSS to manipulate it instead (if re-renders are an issue).

What do you think?