Tagless component challenge after Glimmer update


#1

Due to a very specific use case, I need to be able to take a newly created tagless component and insert it before a marker div in my html. The tagless component will be rendering a block of arbitrary content. Here’s an example of how the generated markup might look:

<body>
<!-- Begin Tagless Component -->
<span>1</span>
<span>2</span>
<span>3</span>
<!-- End Tagless Component -->
<div data-marker>
<div class="other-markup></div>
<div id="ember1001">
  <!-- Main Ember Application -->
</div>
</body>

Attempt 1

// element === <div data-marker>
componentInstance.appendTo(element);
Ember.run.next(this, function() {
  Ember.$(element).contents().unwrap();
  element.remove();
} );

This worked before updating to Glimmer. Now I’m getting this error: Uncaught DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.

Attempt 2

// element === <div data-marker>
var fragment = document.createDocumentFragment();
componentInstance.renderer.appendTo(componentInstance, fragment);

Ember.run.next(this, function() {
  element.parentElement.insertBefore(fragment, element);
} );

This fails with the same error.

Attempt 3

// element === <div data-marker>
var fragment = document.createDocumentFragment();
componentInstance.renderer.appendTo(componentInstance, fragment);

Ember.run.later(this, function() {
  element.parentElement.insertBefore(fragment, element);
},1000 );

This at least appends the item, but of course it circumvents part of Glimmers processing. When the component eventually rerenders after an update, It fails with a similar error: DOMException: Failed to execute 'insertBefore' on 'Node': The node before which the new node is to be inserted is not a child of this node.

Both errors are related to the parent reference not being correct. In the first example, jQuery is forcing a new parent. When using the fragment (attempts 2 & 3), the first/last nodes of the bounds aren’t considered part of that fragment.

I’m not sure if this is even possible, but any suggestions on getting this working. I’m working in a very managed environment, so hacks are workarounds are welcome.


#2

At first glance, it looks like you might be using some private APIs (i.e.: component.renderer) that changed from pre-Glimmer2 to post-Glimmer2.

That being said, your use case sounds awfully like Ember Wormhole — have you tried that addon? If you’ve tried and it doesn’t work with your use case, it might be worth looking at how they render to other destinations as a source of inspiration.


#3

I’m on 2.11.0.beta1. I was only using Component.renderer.appendTo because one of the assertions from Component.appendTo checks to see if the element is an existing view. It does this by trying to use element.matches('.ember-view') and fragments don’t have matches.

I’ve looked into Ember Wormhole, and what I’m doing it quite similar. They’re having the same problem though. For example: https://github.com/yapplabs/ember-wormhole/issues/66 After Glimmer, it requires that extra div which I need to avoid.