0

I was testing out the data() method of jQuery which seems to be very powerful. This is actually for testing out a fixture I'm going to be making for a unit test (that parses out JSON elements by replacing the single quotes with double quotes).

var test = $('#test');
console.log(test.data('table[data-table-values]')); 
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="test" data-table-values="'{'header': ['value1', 'value2']}'"></table>

It returns undefined. However from my understanding this should be returning what the selector is, which in this case should be: '{'header': ['value1', 'value2']}'

Am I missing something?

edit: For reference I am testing against a function that does this:

function parseStuff(str) {
  return JSON.parse(
    str
      .substring(1, (str.length - 1))
      .replace(/'/g, '"')
  );
}

but the thing is, whats getting passed to is in controller/container (My Rails knowledge is limited so im going on what I can read). but for example some of the code looks like:

<instance of container/controller>.data('tableValues')

where 'tableValues is defined as a selector earlier on in the code, and the instance of container/controller is probably the table object itself I'd assume:

tableValues: 'table[data-table-options]' //A bunch more of these selectors are defined

So essentially im trying to set up a HTML fixture I can test this against. The HTML I posted was how it appears in chrome dev tools (obviously with a lot more stuff in the table element, but im just focusing on this selector in particular)

2
  • Your function looks fine, but substring will only work if you're always wrapping the value in quotes. Regarding the Rails, it's separate from JavaScript. You may want to open a new question to see what's going on in your Ruby. I'd need to see more to understand what you're doing. Commented Mar 22, 2017 at 23:02
  • Right, so I guess thats what it's doing. Since the function DOES work im just unit testing against it. I guess I just didn't understand why my jsfiddle didn't work as it's definitely passing table[data-table-values] through the function. So I didn't know if it would bring along double quotes or not...and why it didn't work when I did it. BTW I say rails but these are javascript files within rails Im talking about. Commented Mar 22, 2017 at 23:05

2 Answers 2

3

Retrieving data-* value

You refer to the attribute as table[data-table-values], which is incorrect on two accounts:

  1. table[] is not necessary. I'm not sure why you were using that. This isn't a selector, this is a property lookup.
  2. data-table-values should be table-values. Your HTML attribute is called "data-table-values", but the .data() lookup does not need that for any of the HTML data-* attributes.

The end result of both of these is to have .data('table-values') as evidenced in the example at the bottom.

If you wanted to look up the actual attribute value, then you would need to include the data- prefix, because you're searching for that specific HTML attribute; e.g., $test.attr('data-table-values'), but it's against common practice to do this for data-* attributes.

One thing you should note about the .data() method is that, it operates in memory. It doesn't update your HTML. If you use any sort of inspector you would see that setting $test.data('foo','bar'), it does not bind a foo attribute to the element, nor modifies the DOM, it manages the value internally to jQuery.

Fixing JSON

To use the value as JSON, you need to store it as wellformed JSON, right now you're using single quotes as the encapsulating JSON string delimiter '{'':[]}' and also to delimit the object keys. You must use double quotes for valid JSON.

In the example below, I trim off your leading and ending single quotes (') and then replace all the single quotes around the keys with double quotes ". I broke this into several lines for clarity, but could be condensed into several lines.

Note: if the JSON is valid and properly stored in the data-* attribute, then the client wouldn't need to do so much work scrubbing it and the code would be much more simpler

var $test = $('#test');
var str = $test.data('table-values'); // <=== was:"table[data-table-values]"
console.log('data-* value:', str);

// format to a valid JSON string
str = str.replace(/^'+/, ''); // remove leading single quote
str = str.replace(/'+$/, ''); // remove ending single quote
str = str.replace(/'/g, '"'); // use double quotes
console.log('Replaced single quotes:', str);

// make JS object
var obj = JSON.parse(str);
console.log('obj:', obj);
console.log('obj.header[1]:', obj.header[1]);

// make JSON string
console.log('JSON:', JSON.stringify(obj));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="test" data-table-values="'{'header': ['value1', 'value2']}'"></table>


Better HTML

Here is an example per @guest271314's suggestion, which demonstrates having well-formed JSON in your HTML.

Notice there are far fewer lines (only one required to get the JSON object). Provided is the jQuery and the ES6 equivalent:

// jQuery
var obj = $('#test').data('table-values');
console.log('obj:', obj);
console.log('obj.header[1]:', obj.header[1]);
console.log('JSON.stringify(obj):', JSON.stringify(obj));

// ES6
var obj2 = JSON.parse(document.querySelector('#test').dataset['tableValues']);
console.log('obj2:', obj2);
console.log('obj2.header[1]:', obj2.header[1]);
console.log('JSON.stringify(obj2):', JSON.stringify(obj2));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="test" data-table-values='{"header": ["value1", "value2"]}'></table>

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

16 Comments

Why use .replace() where you could use element.dataset.tableValue and JSON.parse()? Valid JSON is mentioned at description though the value of data-* attribute at html at Answer is not valid JSON
This makes sense, I was just going off a function I was unit testing against: (Ill post the function in the edit) if you can comment on why it shouldn't work/etc...
@guest271314 That wouldn't work, what you're suggesting is JSON.parse( document.getElementById('test').dataset['tableValues'] ); the value is still malformed JSON (as you noted). If it was valid, there wouldn't need to be any replace() above.
No that is not what am suggesting. Correct html and valid JSON within html. Will post Answer when able. There is no reason for either html or JSON to be malformed or invalid
I should add that if it was valid JSON in the attribute, then what @guest271314 is suggesting would work, however it also wouldn't be widely supported across browsers, since it's a newer property. Suffice to say IE11+
|
2

The issue is because you need to provide the attribute name, minus the data- prefix, to the data() method, not the element selector. Try this:

var $test = $('#test');
console.log($test.data('table-values'));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="test" data-table-values="'{'header': ['value1', 'value2']}'"></table>

Also note that if you provide the attribute as HTML encoded JSON then jQuery will automatically deserialise it for you so that you can immediately work with the object's properties:

var $test = $('#test');
var obj = $test.data('table-values')
console.log(obj);
console.log(obj.header[0]);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="test" data-table-values="{&quot;header&quot;: [&quot;value1&quot;,&quot;value2&quot;]}"></table>

12 Comments

Why the downvote? Please let me know if I've misunderstood the question.
Did not cast down vote; note neither attribute value at html is JSON
@guest271314 you're correct that the first one isn't as that is what the OP was originally using. My second example is, it's just HTML encoded so that the " it contains does not interfere with the HTML attributes.
Use '' following = surrounding value to use "" within attribute value. Also two identifiers at data-* camel cased at get
I like the answer myself as it shows how an alternative works and provides insight.
|

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.