Can a backdraft component contain another backdraft component?

47 Views Asked by At

OK say I have a backdraftjs component Box

class Box extends Component {
  bdElements() {
    return e.div(
      {style: border: "1px solid black"},
    );
  }
}

and another Jack

class Jack extends Component {
  bdElements() {
    return e.h1(
      'hello my name is Jack'
    );
  }
}

Is there a way to create a component that puts Jack in Box?

class JackInBox extends Component {
  bdElements() {
    ????
  }
}

I don't think that's possible, is it?

2

There are 2 best solutions below

0
On BEST ANSWER

You can pass custom components as a child similar to how you pass normal elements. eg.

e("div",
  e("p", "Hello World!")
)

In your code e.div(...) is a shortcut for e("div", ...). You can pass a your custom component instead of "div".

e(Box,
  e(Jack)
)

const { e, Component } = bd;

class Box extends Component {
  bdElements() {
    return e.div(
      { style: { border: "1px solid black" } }
    );
  }
}

class Jack extends Component {
  bdElements() {
    return e.h1(
      "hello my name is Jack"
    );
  }
}

class JackInBox extends Component {
  bdElements() {
    // custom components cannot be used as root, so use a div wrapper
    return e.div(
      e(Box,
        e(Jack)
      )
    );
  }
}

bd.render(JackInBox, "root");
<script crossorigin src="https://unpkg.com/[email protected]/dist/lib-umd.js"></script>
<div id="root"></div>

By default children passed to a component are appended to the root element of the component.

0
On

It is possible via several methods. Which method to use depends on the aims of the component.

The op question, "is there a way create a component that puts Jack in Box" is followed by a code snip that creates such a component by subclassing Component. Presumably op's question is asking "is there a way to combine the already-defined Box and Jack components to create a third kind of component, namely, JackInBox. This is sort of a contrived and fuzzy example of composition (https://en.wikipedia.org/wiki/Composition_over_inheritance). A class that's both a Box and a Jack doesn't really make logical sense. The other alternative is to create a "Jack in Box" component by a Box component containing a Jack component.

Though not optimal, let's go ahead and implement via composition. Here's Jack:

class Jack extends Component {
  bdElements() {
    return e.h1({}, 'hello my name is Jack');
  }
}

Next, let's define a generic Box. In order to be useful as a base class, Box should have a nonempty public API (otherwise, why derive from it to begin with?).

class Box extends Component {
  constructor(kwargs){
    super(kwargs);
    this.clickCount = 0;
  }
  someMethod() {
    return `you clicked me ${++this.clickCount} times`;
  }
  bdElements() {
    return e.div({
      bdOn_click:e=>alert(this.someMethod()),
      style: 'border: 2px solid black;'
    });
  }
}

Finally, let's make a JackInBox class which behaves exactly like a Box, but has a Jack in it.


class JackInBox extends Box {
  bdElements() {
    return e.div({
      bdOn_click:e=>alert(this.someMethod()),
      style: 'border: 2px solid black;'
    }, e(Jack));
  }
}

Of course this is quite artificial, but imagine that Box had an extensive public api, then simply rewriting the bdElements function to get all of that API in a new component might be worth while.

That said, I find the example above a bit confused because it seems you ought to be able to just put stuff in a box. Indeed you can, let's try again and just use the original Box without making the new class JackInBox. This is an example of containment, to wit, the box below contains a Jack.

let box = render(Box, {}, "root");

// insert Jack; if not explicitly stated, children or appended to the root node
box.insChild(Jack);

Maybe later, we need to define other things to go in the box. For example Jill:

class Jill extends Component {
  bdElements() {
    return e.h1({}, 'hello my name is Jill');
  }
}

Put Jill in the box with Jack; hopefully they still like each other after all these years.

box.insChild(Jill);

A more-complex component that includes a box in which to insert children; therefore, we must tell backdraft where to insert said children:

class Box4 extends Component {
  bdElements() {
    return e.div(
      {style: 'border: 2px dashed red;'},
      e.p("the box below can contain any number of children"),
      e.div({
        style: 'border: 2px solid red;',
        bdAttach:'bdChildrenAttachPoint'
      })
    );
  }
}

let box4 = render(Box4, {}, "root");
box4.insChild(Jack);
box4.insChild(Jill);

All of these example can bee seen in the live pen at https://codepen.io/rcgill/pen/jOBbELY