Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can the DOM be a DAG or must it remain a tree?

Tags:

javascript

dom

It's puzzling. I'm expecting that just googling for the question in the subject line would provide a clear answer, but since not even a hint of an answer comes up, I'm asking.

The code below uses D3 for convenience, but the question is about the DOM. Feel free to use the (lesser IMHO) jquery or (the far-lesser) barebone DOM manipulation code, if you prefer, to answer.

A number of DIVs appear on the left (). While hovering one of the DIVs is magnified on the right ().

function magnify(i) {
    return function() {
        var right = d3.select("right");
        right.selectAll("*").remove();
        right.append("magunit")
             .html("<h2>" + i + "</h2>");
    }
}
for(i=0; i<256; i++) {
    var unit = d3.select("left").append("unit")
                 .on("mouseenter",magnify(i));
    unit.html("<h2>" + i + "</h2>");
}
html, body { width: 100%; height: 100%; margin: 0; }
mycontainer { width: 100%; height: 100%; display: flex; flex-flow: row; }
left { display: flex; flex-flow: row wrap; flex: 1; overflow-y: auto;}
right { display: flex; flex-flow: row; flex: 1; }
unit { flex: 1 1 auto; width: 80px; height: 60px; border: solid 1px black; }
<script src="https://d3js.org/d3.v5.min.js"></script>
    <mycontainer><left></left><right></right></mycontainer>

Is it necessary to recreate each DIV? What does the standard say about pointing to an existing DIV from two leaves, effectively making the DOM a Directed Acyclic Graph (DAG) rather than a tree?

can-the-dom-be-a-dag

Clarification, in reply to Kaiido's comment

I'm using a <unit> here in place of something arbitrarily complex to keep the code brief. The point would be to move pointers rather than constantly recreate the (arbitrarily complex) unit structures. Hence "just change the text inside <h2>" doesn't cut it, but "switch to SVG and utilize <use>" is right on.

Relevant

  • Shadow DOM
like image 508
Vrokipal Avatar asked Sep 13 '25 22:09

Vrokipal


2 Answers

I think you're asking whether the same element can be the child of multiple elements (e.g. one div is a child of two divs who are themselves siblings, for example), then the simple answer is No.

Think about it - if you had to write the HTML by hand, how would you write that using markup? HTML is fundamentally a written markup language, and the DOM is just a way of representing a HTML document programmatically so that scripts can manipulate it.

We are constrained by that, because whatever is within the DOM must be expressible as valid HTML, and vice-versa. Ultimately the browser parses the HTML document in order to know what to display. The structure of the document is (must be) strictly a tree because in HTML (and XML) child elements are created by placing them within their parent element (i.e. nesting). There is no way to express a multi-parent relationship using this format.

If we were designing the web again today we might do it differently, but this is part of the legacy we've got from nearly 30 years ago - when JavaScript wasn't even a thing.

If you want a general reference about the relationship between the DOM and HTML documents, I would recommend reading https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/… to begin with.

See also https://w3.org/TR/2004/REC-DOM-Level-3-LS-20040407/load-save.html . This the W3C spec describing how a DOM object must be serialisable both from and to XML (of which HTML is, of course, a specific variety). If it's serialisable to XML, then it must be representable as a hierarchical tree, because that's what XML requires.

And https://dom.spec.whatwg.org/#nodes is the current living standard, describing how the DOM is a hierarchical tree of nodes.

like image 63
ADyson Avatar answered Sep 16 '25 12:09

ADyson


No. I have put it to test via following:

var testdiv = document.createElement("div");
testdiv.innerHTML="Im testing";
document.body.insertBefore(testdiv,document.body.childNodes[0]);

so my testdiv appended to top of the body. Now when append exact same node to end of body:

document.body.append(testdiv);

Node is removed from top and appended to bottom.

However, there is a workaround. Nodes in javascript are objects, therefor you can add additional parameter to them. You can use it to set an ID for each node element, you can store which elements are in which ID in an array. As a basic example:

var map=[];
var testdiv = document.createElement("div");
testdiv.innerHTML="Im testing";
testdiv.myID=1;
if (!map[1]) map[1]=[];
map[1].push(testdiv);

document.body.append(testdiv);

var testdiv2=testdiv.cloneNode(true);
testdiv2.myID=testdiv.myID;
document.body.append(testdiv2);
if (!map[1]) map[1]=[];
map[1].push(testdiv2);

Now if you query map for elements, it will return 2 nodes with ID 1. and this map array is connected to those nodes inside DOM. You are able to get ID of nodes in your DOM by looking at their myID.

like image 40
Armin Nikdel Avatar answered Sep 16 '25 11:09

Armin Nikdel