0

This question and this question explain how to compare the contents of two jQuery elements/objects?

However, we need to compare the contents as well as their attributes.

Element 1:

<div id="A" width="200" height="200" style="stuff"></div>

Element 2:

<div id="B" width="300" height="300" style="differentstuff"></div>

Element 3:

<div id="C" width="200" height="200" style="stuff"></div>

Assume all three elements have the same content as tested by the $.html() method described in the linked answers.

Elements 1 and 3 should match as equal while element 2 should not be equal to elements 1 and 3.

Is there a native way to do this, or do you have to manually check each attribute? Ideally, there would be a way to get the "attribute content" of an element as way for comparison.

fiza khan
  • 1,280
  • 13
  • 24
Crashalot
  • 33,605
  • 61
  • 269
  • 439

1 Answers1

1

You can check the element's outerHTML and check that the text from the first < to > (that is, the tag and attribute string) is identical:

const elmToAttribString = elm => elm.outerHTML.match(/<[^>]+>/)[0];
const check = (elm1, elm2) => elmToAttribString(elm1) === elmToAttribString(elm2);

const [d1, d2, d3] = $('div');
console.log(check(d1, d2));
console.log(check(d1, d3));
console.log(check(d2, d3));
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="A" width="200" height="200" style="stuff"></div>
<div id="A" width="300" height="300" style="differentstuff"></div>
<div id="A" width="200" height="200" style="stuff"></div>

Though, note that this checks attributes of an element in the order they're listed in the HTML, not properties (and that you really shouldn't have elements with duplicate IDs in a single document in the first place - that's invalid HTML).

If the attributes can be in different orders or can have different separators between them (eg, something other than just a single space between attribute-value pairs), then you'll have to extract each attribute to check, perhaps transforming the .attributes into a stringified object:

const elmToAttribString = elm => JSON.stringify(
  [...elm.attributes]
    .map(({ name, value }) => ({ name, value }))
    .sort((a, b) => a.name.localeCompare(b.name))
);
const check = (elm1, elm2) => elmToAttribString(elm1) === elmToAttribString(elm2);

const [d1, d2, d3] = $('div');
console.log(check(d1, d2));
console.log(check(d1, d3));
console.log(check(d2, d3));
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
first item has different order, weird spacing:
<div width="200" id="A"        height="200" style="stuff"></div>
<div id="A" width="300" height="300" style="differentstuff"></div>
<div id="A" width="200" height="200" style="stuff"></div>
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • thanks for the answer, you're right about the IDs. that was a typo, now fixed. – Crashalot Feb 06 '19 at 05:07
  • hi there, what's the `...` notation mean in `[...elm.attributes]`? never seen this before in JS. also is there a benefit to declaring these as `const` instead of functions? – Crashalot Feb 06 '19 at 08:57
  • It transforms the array-like `.attributes` object into a *true* array, allowing array methods like `.map` and `.sort` to be called on it. Longer version: `Array.from(elm.attributes)`. I generally prefer arrow functions, especially when the return value is generated immediately - it cuts down on syntax noise and is a bit more efficient, it also distinguishes that the function is only going to be called normally, not instantiated. – CertainPerformance Feb 06 '19 at 09:07
  • Interesting, thanks so much. Would you be interested in small consulting jobs on JS questions like this? More details: https://myhotpot.io/jobs. Please share when you read this comment so it can get deleted. Thanks! – Crashalot Feb 06 '19 at 09:22
  • Ok, I'll check it out – CertainPerformance Feb 06 '19 at 09:27