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?

7
  • 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. Commented Feb 24, 2019 at 4:32
  • @Ry- There is more than one correct approach for setting JSON at HTML element attribute value. Commented Feb 24, 2019 at 5: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. Commented Feb 24, 2019 at 5: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. Commented Feb 24, 2019 at 5:53
  • Related Pass JS-arguments from HTML; see also change data-unknown attribute value Commented Feb 24, 2019 at 6:15

2 Answers 2

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.

Sign up to request clarification or add additional context in comments.

Comments

-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>

7 Comments

This answer is actually working. I am getting a well formed output. I am getting <a href="#" data-presentations="[{&quot;name&quot;:&quot;Cremas&quot;,&quot;measures&quot;:[&quot;5g&quot;,&quot;15g&quot;]}]">Medicine1</a> after using single quotes like @guest271314 suggest
@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- 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: “There are no single quotes in valid JSON” is utterly wrong.
@Ry- You have not provided any constructive input thus far at this question. Nobody asked you for your predisposed and biased opinion.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.