WebReflection / hyperHTML

A Fast & Light Virtual DOM Alternative
ISC License
3.07k stars 113 forks source link

Patch a node or multiple nodes #261

Closed luwes closed 6 years ago

luwes commented 6 years ago

Having this html structure, not created with hyperHTML.

Before:

<todo-app>
  <style type="text/css"></style>
  <span>Must be kept here.</span>
</todo-app>

After:

<todo-app>
  <style type="text/css"></style>
  <span>Must be kept here.</span>

  <div>Following divs created with hyperHTML</div>
  <div>Added dynamic content ${Date.now()}</div>
  <div>Another child w/ dynamic ${count++}</div>
</todo-app>

Is it possible to append a child node or multiple nodes and subsequently have them re-render in the same spot with a wire or bind? Can't seem to get my head around it.

WebReflection commented 6 years ago

This seems like one question where the old adopt might have helped, although it's not easy to have a proper adopt if you don't control the source html generator (i.e. via viperHTML) so one option that comes up could be to grab node content, map its children, and enrich the content.

function rebind(node) {
  var bind = hyperHTML.bind(node);
  bind.before = Array.from(node.children);
  return bind;
}

var bound = rebind(document.querySelector('todo-app'));
bound`
  ${bound.before}
  <div>Following divs created with hyperHTML</div>
  <div>Added dynamic content ${Date.now()}</div>
  <div>Another child w/ dynamic ${count++}</div>
`;

You could use node.childNodes if you know the content has also relevant text content.

The idea is that you won't mess up with pre-existing content, but you can pollute with extra stuff.

Remember, you should create your render (aka bound) reference once, or you'll keep grabbing nodes and appending new.

luwes commented 6 years ago

Thanks for the thorough answer @WebReflection!

I came up with this little snippet that also seems to work although it's more hacky but keeps the ability to add elements to the parent later without hyperHTML if it's needed.

One thing that is needed there is pass an empty array wire(this)${[]}` which outputs a hyperHTML id comment and subsequent renders will just update that referenced wire.

I hope it's intended behavior, otherwise please let me know :smiley:

https://jsfiddle.net/luwes/xcz3d79f/

Also relevant to this issue is the following change in this PR where this technique is used in practice. https://github.com/Wildhoney/Switzerland/pull/22/files#diff-c220d64bd73b0920d12df0d0bdbef7fbR91

WebReflection commented 6 years ago

@luwes that's another way, but it's less declarative/handy than the one I've proposed.

The good thing is that there is some workaround, no matter what's the use case 👍

luwes commented 6 years ago

Awesome, verified it works. https://jsfiddle.net/luwes/08h6a3k7/

I expected the later appended element would be removed by hyperHTML but it's luckily not the case. Only side effect is that the before children will be re-rendered with rebind which could be unwanted.

Either way super glad it works!