2

I am creating two links dynamically, one using template literals and another using document.createElement(), in both I need to pass as an attribute data-presentation an object as a string of characters. But I get different results.

When I inspect the link created using template literals I get the following result

<a href="#" data-presentations="[{" name":"cremas","measures":["5g","15g"]}]"="">Click</a>

And because it is badly formed when I need to parse it, I get an error return.

On the other hand, the link created using document.createElement () upon inspection returns the following result.

<a href="#" data-presentations="[{&quot;name&quot;:&quot;Cremas&quot;,&quot;measures&quot;:[&quot;5g&quot;,&quot;15g&quot;]}]">Another click</a>

And then when I need to parse it, it works properly.

Please take a look at the way are creatied the links

const root = document.querySelector('#root');
const object = {
    "id": 4,
    "name": "Medicine1",
    "code": "1234",
    "status": true,
    "location": "E4-2",
    "genericName": "SomeGenericName",
    "presentations": [
        {
            "name": "Cremas",
            "measures": [
                "5g",
                "15g"
            ]
        }
    ]
};

const link = `<a href="#" data-presentations="${JSON.stringify(object.presentations)}">Click</a>`

const anchor = document.createElement('a');

anchor.href = '#';
anchor.setAttribute('data-presentations', JSON.stringify(object.presentations));
anchor.textContent = 'Another click';

root.innerHTML = link;

document.body.appendChild(anchor)
<div id="root"></div>

What can I do so that the link created through template literals is correctly formed?

Mario
  • 4,784
  • 3
  • 34
  • 50
  • 1
    Untagged template literals are just string concatenation. They don’t know you’re trying to make HTML. Why not just keep using the DOM approach? It’s the correct one. – Ry- Feb 24 '19 at 04:32
  • @Ry- There is more than one correct approach for setting `JSON` at HTML element attribute value. – guest271314 Feb 24 '19 at 05:25
  • @guest271314: Indeed, but given that you haven’t provided one you can see why I would recommend the simplicity and reliability of the DOM. – Ry- Feb 24 '19 at 05:49
  • @Ry- _"Indeed, but given that you haven’t provided one"_ What are you talking about? That is a false statement. The last sentence at your first comment is also false. There is no _"the correct one"_. The answer achieves just that. The `JSON` can be hardcoded at HTML as well. The only issue with the code at the question is the use of double quotes surrounding the attribute value within the template literal. – guest271314 Feb 24 '19 at 05:53
  • Related [Pass JS-arguments from HTML](https://stackoverflow.com/q/35782121/); see also [change data-unknown attribute value](https://stackoverflow.com/q/32035386/) – guest271314 Feb 24 '19 at 06:15
  • This question has been marked as duplicate but they are different problems – Mario Feb 24 '19 at 14:45
  • @user615274 The solution to your current question is posted at an answer to one of your previous questions. [Expand object literal as html5 data- attributes](https://stackoverflow.com/a/46632997/). Did not delete own answer at this question, and thus the answer here is still applicable. – guest271314 Feb 24 '19 at 17:00

2 Answers2

2

You would need to escape your JSON according to the HTML context it’s used in. Double-quoted attribute value? Escape ampersands and double quotes:

const escapeDoubleQuoted = text =>
    text.replace(/&/g, '&amp;')
        .replace(/"/g, '&quot;');

Single-quoted attribute value? Escape ampersands and single quotes:

const escapeSingleQuoted = text =>
    text.replace(/&/g, '&amp;')
        .replace(/'/g, '&#39;');

If you wanted to include it in a <script>, you would need to escape < as \x3c; and so on. So a correct version of the HTML-building approach would be:

const link = `<a href="#" data-presentations='${escapeSingleQuoted(JSON.stringify(object.presentations))}'>Click</a>`

The DOM is usually preferable when you don’t introduce HTML-building libraries because you don’t have to think about this.

Ry-
  • 218,210
  • 55
  • 464
  • 476
-2

What can I do so that the link created through template literals is correctly formed?

Use single quotes ' surrounding JSON set as value of an HTML attribute

const root = document.querySelector('#root');
const object = {
    "id": 4,
    "name": "Medicine1",
    "code": "1234",
    "status": true,
    "location": "E4-2",
    "genericName": "SomeGenericName",
    "presentations": [
        {
            "name": "Cremas",
            "measures": [
                "5g",
                "15g"
            ]
        }
    ]
};

const link = `<a href="#" data-presentations='${JSON.stringify(object.presentations)}'>Click</a>`

const anchor = document.createElement('a');

anchor.href = '#';
anchor.setAttribute('data-presentations', JSON.stringify(object.presentations));
anchor.textContent = 'Another click';

root.innerHTML = link;

document.body.appendChild(anchor);

console.log(JSON.parse(root.firstElementChild.dataset.presentations));
<div id="root"></div>
guest271314
  • 1
  • 15
  • 104
  • 177
  • 1
    This answer is actually working. I am getting a well formed output. I am getting `Medicine1` after using single quotes like @guest271314 suggest – Mario Feb 24 '19 at 14:41
  • 1
    @user615274: It’s “working” because there are no ampersands and no single quotes in your JSON. It’s extremely fragile and I wouldn’t recommend you use it for anything, because it’s an XSS vulnerability waiting to happen. – Ry- Feb 24 '19 at 16:51
  • @Ry- Move on. You should scrub your own comment. There are no single quotes in valid `JSON` surrounding property names or property values. If you have found an XSS vulnerability in the code publish your results. Otherwise stop spreading intentional falsehoods, unless you cannot help yourself. In which case, go get some help. Your little symbol must be cubic zirconia. – guest271314 Feb 24 '19 at 16:54
  • @guest271314: “There are no single quotes in valid JSON” is utterly wrong. – Ry- Feb 24 '19 at 16:54
  • @Ry- You have not provided any constructive input thus far at this question. Nobody asked you for your predisposed and biased opinion. – guest271314 Feb 24 '19 at 16:55
  • @guest271314: If you can’t take accurate criticism, don’t write dangerously incomplete advice. – Ry- Feb 24 '19 at 17:07
  • @Ry- Critics can go find the nearest bridge and test the validity of gravity. There is nothing "dangerous" about the approach at the answer. Will do what please. Don't be a hater. – guest271314 Feb 24 '19 at 17:12