Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible in JavaScript to get unique references to unique DOM elements (for use as unique keys in an object)?

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?

like image 907
Ed_Johnsen Avatar asked Oct 26 '25 09:10

Ed_Johnsen


2 Answers

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>
like image 57
Keith Avatar answered Oct 27 '25 22:10

Keith


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>
like image 20
CertainPerformance Avatar answered Oct 27 '25 23:10

CertainPerformance