While attempting to make my own methods for two-way data binding, I thought I'd had a great idea. As part of that idea, I tried to use DOM element references as keys in a JavaScript object that would hold data related to each element.
Unfortunately, it seems that JavaScript references to DOM elements are generic (with respect to a tagName [like p]).
For example:
function testScenarios(){
// create references to DOM objects
var a = document.getElementById("id_a"),
b = document.getElementById("id_b");
// create and fill a test object
var testObj = {};
testObj[a] = "a"; // use the reference to p#id_a as a key for the value "a"
testObj[b] = "b"; // use the reference to p#id_b as a key for the value "b"
testObj[a.id] = "aId"; // use the id captured from the reference to p#id_a as a key for the value "aID"
testObj[b.id] = "bId"; // use the id captured from reference to p#id_b as a key for the value "bId"
testObj["0"] = a; // use "0" as a key for a value that is the reference to p#id_a
testObj["1"] = b; // use "1" as a key for a value that is the reference to p#id_b
// store test values
var testResults = {
does_a_equal_b : (a===b),
does_aId_equal_bId : (a.id===b.id),
does_objA_equal_objB : (testObj[a]===testObj[b]),
does_objAid_equal_objBid : (testObj[a.id]===testObj[b.id]),
does_obj0_equal_obj1 : (testObj["0"]===testObj["1"]),
what_is_a : a,
what_is_b : b
}
// run the tests and display results
for(testKey in testResults){
document.getElementById(testKey).innerHTML = testResults[testKey];
}
document.getElementById("the_object").innerHTML = JSON.stringify(testObj, null, 4);
}
p {width:400px;}
p:nth-child(odd){background:#ccc;}
span {float:right; font-weight:800;}
p:nth-child(8){background:#c63;}
p:nth-child(10){background:#c63; height:40px;}
p:nth-child(11){background:#c63; height:40px;}
p:nth-child(12){background:#c63; height:60px;}
<p id="id_a">paragraph element a</p>
<p id="id_b">paragraph element b</p>
<button onclick="testScenarios()">Run the tests</button>
<p>a === b? (expecting false)<span id="does_a_equal_b"></span></p>
<p>a.id === b.id? (expecting false)<span id="does_aId_equal_bId"></span></p>
<p>testObj[a.id] === testObj[b.id]? (expecting false)<span id="does_objAid_equal_objBid"></span></p>
<p>testObj["0"] === testObj["1"]? (expecting false)<span id="does_obj0_equal_obj1"></span></p>
<p>testObj[a] === testObj[b]? (expecting false)<span id="does_objA_equal_objB"></span></p>
<p>ok, but... why?</p>
<p>What is a? (expecting somethihng like p#id_a, or a number)<span id="what_is_a"></span></p>
<p>What is b? (expecting somethihng like p#id_a, or a number)<span id="what_is_b"></span></p>
<p>What is testObj?<span id="the_object"></span></p>
<p>Sooooo... even though:<br>a !== b,<br>testObj[a] === testObj[b].<br>?¯\_(ツ)_/¯?<br><br>Is there some way to get the unique aspects of references a and b out of those references for later use?</p>
Is there a method for obtaining unique identifiers associated with each reference to a DOM object?
WeakMap's are really handy for this.
There similar to Map's, but will get removed & garbage collected when the Element is destroyed.
Below is a simple working snippet. For testing purposes I'm just creating a simple generated string that I attach to the element. Then from the click handler I'm reading this info back. The value can be objects too, for a more complicated data structure.
const data = new WeakMap();
let count = 0;
for (const el of document.querySelectorAll("div")) {
count += 1;
data.set(el, `This is data for item ${count}`);
}
document.body.addEventListener("click", evt => {
const info = data.get(evt.target);
if (info) document.querySelector("#clicked").innerText = info;
});
div {
border: 1px solid black;
padding: 4px;
margin: 4px;
}
<div id="items">
<div>one</div>
<div>two</div>
<div>three</div>
<div>four</div>
</div>
<div id="clicked"></div>
Javascript object keys are always strings, so if a is an element, testObj[a] won't work, because the element will be coerced to a string, which may well have the same value as some other element's coerced string. Use a Map instead, which is similar to an object, but can have keys of any value, including HTMLElements:
// create references to DOM objects
var a = document.getElementById("id_a"),
b = document.getElementById("id_b");
// create and fill a test object
const map = new Map();
map.set(a, 'a');
map.set(b, 'b');
map.set(a.id, "aId");
map.set(b.id, "bId");
map.set('0', a);
map.set('1', b);
map.set(a.id, "aId");
// store test values
var testResults = {
does_a_equal_b: (a === b),
does_aId_equal_bId: (a.id === b.id),
does_objA_equal_objB: (map.get(a) === map.get(b)),
does_objAid_equal_objBid: (map.get(a.id) === map.get(b.id)),
does_obj0_equal_obj1: (map.get('0') === map.get('1')),
what_is_a: a,
what_is_b: b
};
console.log(testResults);
<p id="id_a">paragraph element a</p>
<p id="id_b">paragraph element b</p>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With