Skip to main content

Error: Child Already Exists on Parent

You might come across this error:

Uncaught Error: Cannot add child node Shape (2717f16e-682f-4cb1-bbc2-4fe34d3ec2de)
to parent node Shape (921cf9e6-7970-4702-aa4a-3cc1cc8f8e59).
This child already exists on this parent. The child cannot be added again.

or

Uncaught Error: Cannot add child node Shape (3a43596c-c9a3-4158-8ab0-110442f701d5)
to parent node Shape (68004c48-6ac9-43f8-8430-e28b09388fa9). This child already exists
on other parent node: Shape (dbbfe9ed-d44e-471e-8127-d2230d09dc8e).
Remove the child from the other parent first.

In m2c2kit, a child node can have only one parent node. In other words, a node can't "have two parents at once." If you add a child node to a parent node, but the child node already has a parent, you'll get an error. Similarly, if you add a child node to a parent node for a second time, you'll also get an error.

Demonstration of the problem

In the simple example below, there are two scenes. After pressing the start button in sceneOne, the task is presented in taskScene. A blue circle will randomly appear in one of two rectangles. The task is to tap the circle. After you tap the circle, an animation will briefly grow and shrink it. Then the task will repeat by presenting taskScene again.

Once you tap the circle, however, you will get an error. The problem is in this code:

taskScene.onSetup(() => {
const rectangleNumber = RandomDraws.SingleFromRange(1,2);
if (rectangleNumber === 1) {
console.log("Adding the circle to the top rectangle");
rectangle1.addChild(circle);
} else {
console.log("Adding the circle to the bottom rectangle");
rectangle2.addChild(circle);
}
});

The first time taskScene is presented (after you press start), the onSetup callback places the circle in one of the rectangles. The second time taskScene is presented (after you tap the circle), the onSetup callback tries to place the circle in one of the rectangles again. But the circle already has a parent (the rectangle it was placed in the first time). So you get an error.

Loading...

Solution

The solution is to remove the circle from its parent before adding it to a new parent. Parent nodes have three functions1 to remove children:

  • removeChild(child: M2Node) - remove the specified child.
  • removeChildren(children: M2Node[]) - remove the specified children.
  • removeAllChildren() - remove all children.

In our example, the circle could either be a child of rectangle1 or rectangle2. Rather than checking which rectangle the circle is a child of, we can remove all children (which will include the circle) from both rectangles. Then we can add the circle to the new rectangle:

taskScene.onSetup(() => {
rectangle1.removeAllChildren();
rectangle2.removeAllChildren();
const rectangleNumber = RandomDraws.SingleFromRange(1,2);
if (rectangleNumber === 1) {
console.log("Adding the circle to the top rectangle");
rectangle1.addChild(circle);
} else {
console.log("Adding the circle to the bottom rectangle");
rectangle2.addChild(circle);
}
});

The example now works without error.

Loading...

Footnotes

  1. An important difference between these functions is that removeAllChildren() is idempotent. You can call it multiple times without error. The other two functions will throw an error if you try to remove a child that is not a child of the parent, such as if you already removed the child on an earlier function call and try to remove it again.