I was getting this error and have tracked it down to the following:
class Outer extends Component {
bdElements() {return e.div()}
}
class Inner extends Component {
bdElements() {return e.div('hello how are you')}
}
class ThisWorks extends Component {
bdElements() {
return e.div(
e(Outer, {}, e(Inner))
);
}
}
class ThisDoesNotWork extends Component {
bdElements() {
return e.div(
e(Outer, {}, e.div('hello there'))
);
}
}
window.demo1 = function() {
render(ThisWorks, {}, document.body,'only')
}
window.demo2 = function() {
render(ThisDoesNotWork, {}, document.body,'only')
}
Running demo2()
will produce the error. As you can see the only difference between ThisWorks
and ThisDoesNotWork
is that the former contains e(Inner)
where the latter simply loads a div directly e.div('hello there')
.
Does this make sense? It seems like in almost all other cases you can swap e(ComponentName)
with e.tagname()
interchangeably.
Is there a way to insert rendered content in this situation rather than having to use a separate component?
Consider the element tree given by protected
bdElements()
method ofThisDoesNotWork
:This instructs the framework to do a depth-first traversal and instantiate a DOM tree as follows:
div
nodeOuter
div
node with the text content 'hello there'.Outer
instance created in Step 2.Outer
instance created in Step 2 as a child to thediv
node created in Step 1.Putting a breakpoint at the line the emits the error message, you will see Step 4 fails, so let's investigate that step a bit more.
The documentation for inserting a child into a component is given at https://backdraftjs.org/docs.html#bd-core.classes.Component.insChild and it says the first argument can be either of (1) an element, (2) a constructor derived from Component, or (3) and instance of a Component (of course, also implying, an instance of a constructor derived from Component). But in this case, the code is trying to add a
div
node, which is none of those things.Let's take a step back and think about why this is as it is. The element tree given by the
bdElements
method override of a particular Component-derived class describes the tree of Component instances and/or DOM nodes that comprise an instance of said Component-derived class. To construct that tree, the framework simple executes a depth-first traversal of the that description (i.e., the element tree given bybdElements
). After each node is the tree is completely "visited", the traversal bumps back up to the parent of said node and informs that parent of all if its children. For parents that are DOM nodes, this implies simply adding the children nodes...which are now proper DOM trees...as children of the parent. For Component instances, this implies inserting the children as children of the Component instance. Here is the key: what does it mean to "insert a child into a Component instance"? It means apply the Component methodinsChild
to that child. But it is nonsensical to insert a plain old DOM node as a child of a Component....thats the wrong level of abstraction. Instead, it only makes sense to insert another Component instance of a Child of a Component.Remember: the DOM consequent to instantiating a Component is a tree of DOM nodes that may be decorated with various other Component instances. Those various other Component instances are children of the instantiated components...which is different (a higher level of abstraction) than children of any particular DOM nodes in the tree. And the corollary: the bare DOM notes in the tree consequent to instantiating a Component are not children of the Component, but rather are children of their parent DOM nodes (a lower level of abstraction).