0

I have an HTML element with a data attribute:

<a href="#" data-trigger="{ "rem": "albatros", "ap":1 }'">Remove</a>
<div data-container>
    <p>lorem ipsum<p>
    <p data-rem></p>
</div>

1.

in the data-trigger sometimes(not always) I send a value:

I want to gather all elements that have the attribute data-trigger:

document.querySelectorAll(['data-trigger']).forEach(function (trigger, index) {

and for each of this trigger to get the DOM and JSON value and parse it:

dom = trigger    
value = JSON.parse(trigger.getAttribute('data-trigger'));

I get the DOM reference but for the value I always get null

By using getAttribute do I call again in the DOM ?

  1. Looping thru data-container search for elements which have the attributes one of the keys found in JSON.parse and set their value, the value of the key.

For example:

<p data-rem>albatros</p>
user3541631
  • 3,686
  • 8
  • 48
  • 115

2 Answers2

2

This is not valid JSON String

<a href="#" data-trigger="{'rem': 'albatros'}">Remove</a>

Try:

<a href="#" data-trigger='{"rem": "albatros"}'>Remove</a> <!-- Double quotes in JSON -->

Then:

document.querySelectorAll("[data-trigger]").forEach(function (trigger, index) {
  var val = JSON.parse(trigger.getAttribute('data-trigger'));
  for( key in val){ //Loop through (JSON-)Object
   setInnerElements(val[key], key);
  }
  
});

function setInnerElements(val,key){

document.querySelectorAll("[data-container] > [data-"+ key +"]").forEach(function (el, index) {
   el.innerHTML = val;
  })
}
<a href="#" data-trigger='{"rem": "albatros", "foo":"test1", "bar":"test2"}'>Remove</a>
<div data-container>
<p>lorem ipsum<p>
<p data-rem></p>
<p>lorem ipsum<p>
<p data-foo></p>
<p>lorem ipsum<p>
<p data-bar></p>
</div>
alexP
  • 3,672
  • 7
  • 27
  • 36
  • thanks, and for the second part, what is a efficient way to search for elements that have an attribute name equal with the key in JSON ? – user3541631 Aug 06 '18 at 08:56
  • Edited my answer – alexP Aug 06 '18 at 08:56
  • in JSON, can be multiple key that I don't know prior, so I need to loop in Json an then check, but I think doing loop in loops(json and inside doom loop) is not very efficient, so I'm searching for something optimized; in your example you target just one key – user3541631 Aug 06 '18 at 09:01
  • The real value of such methods is when you don't know in advance what they keys might be. To iterate through all enumerable properties of your parsed JSON, you'll find `Object.keys()` quite useful: `elem[Object.keys(elem)][0]` or use a `for` loop on the `Object.keys()` array, if you have more than one key-value pairs. – tao Aug 06 '18 at 09:27
  • Edited my answer – alexP Aug 06 '18 at 09:38
2

What is currently stopping your script in its tracks is the selector inside querySelectorAll().

It should be '[data-trigger]', not ['data-trigger'].

After you fix it, you'll be able to get all elements with a data-trigger attribute. However, the string you placed in data-trigger attribute won't parse as a JavaScript object (as you probably expect). Your best bet would be to replace quotes with double quotes and double quotes with quotes, making it a valid JSON string and parse it:

<a href="#" data-trigger='{"rem": "albatros"}'>Remove</a>
JSON.parse(elem.getAttribute('data-trigger')) // where elem is the DOM element above

You haven't been exactly clear on what the purpose of this script is but, assuming you want to find a list of DOM elements having 'data-'+foundKey equal to foundVal, you could make the following selector:

document.querySelectorAll('[data-'+foundKey+'="'+foundVal+'"]').forEach(function(el, i){
  console.log(el, i);
})

... but in your case that wouldn't do anything, because you don't have any element with

<x data-rem="albatros"></x>

Here's a working example of what I'm talking about, applied to your markup:

document.querySelectorAll('[data-trigger]').forEach(function (trigger, index) {
  const triggerProp = JSON.parse(trigger.getAttribute('data-trigger')),
        foundKey = Object.keys(triggerProp)[0],
        foundVal = triggerProp[Object.keys(triggerProp)[0]],
        targets = document.querySelectorAll('[data-'+foundKey+']').forEach(function(target, index) {
    console.log(target, 'key:'+foundKey, 'val:'+target.getAttribute('data-'+foundKey));
  });
})
<a href="#" data-trigger='{"rem": "albatros"}'>Remove</a>
<div data-container>
    <p>lorem ipsum<p>
    <p data-rem="test"></p>
</div>

Do note that it only works because the value of data-trigger is valid JSON. If it were not, it would fail miserably. You could guard your script from this risk by a try/catch function that would test the value as JSON first. Another alternative is to use a library that parses relaxed JSON.

tao
  • 82,996
  • 16
  • 114
  • 150