Some few months ago, I took a project which was really nice and made me code happily.
It was a kind of project that had no dependencies specifically jQuery. What do you expect? I had to take the DOM in a vanilla flavour.
In the absence of jQuery and its Data API, I had to access the HTMLElement.dataset
after the program had been fed the data attribute name.
In JavaScript, object properties, when using a dot notation, can only be accessed if the property name satisfies the naming convention of variables—I mean: containing [A-Za-z0-9_$]
. More elaborately, [\w$]+[\d\w$]*
.
The problem was that; the data-attribute in the markup uses hyphen as delimeter, but javascript won't allow this to be just that way in the native Object representation of the dataset. Instead some transformations are done to make it as it should be—camelCase.
That same problem was what I faced. The attribute name being fed to the program was also hyphenated. So I had to do the transformations myself and use index syntax to access it from the HTMLElement.dataset
object.
The Transformation
The transformation came out of few lines of code that made an easy solution.
Thanks to @Order & Chaos Creative
from the comment who made me realize we could actually use regular expression. This problem can be solved with two easy methods.
Method 1
function camelCase(name, delim = '-') {
const list = Array.isArray(data) ? data : data.split(delim)
return list.reduce((res, cur) => res + cur.charAt(0)
.toUpperCase() + cur.slice(1)
)
}
Our delim
argument has a default value which is an hyphen. If the name has already been chunked into an array, we leave it to remain so, else we split it—at every occurrence of the delim
—into an array. The best method to adopt is the array reduce, Array.prototype.reduce
, since we do not need to transform the first word before an hyphen. We take the first char in the next word to upper case and slice out the rest, after which the strings are concatenated.
Method 2
function camelCase(name, delim = '-') {
const pattern = new RegExp((delim + "([a-z])"), "g")
return name.replace(pattern, (match, capture) => capture.toUpperCase())
}
Here we only capture the lowercase letter that comes after an hyphen, then pass an arrow function to the replace
method as callback which takes the original match and the captured group. The captured string is what we need to transform to uppercase.
Application
We remove the "data-" prefix since we don't need it to access any prop in the dataset. It has a length of 5 units. Call the function and eureka!
const name = "data-hello-to-everyone"
const cutStart = 5
const newName = camelCase(name.substring(cutStart))
// newName: "helloToEveryone"
We can now get our property value.
const value = HTMLElement.dataset[newName]
Note: HTMLElement.dataset is not an object literal. It is a DOMStringMap
Object.
interface HTMLElement {
dataset: DOMStringMap;
}
I hope you enjoyed this short lesson. Don't forget to follow me here and on twitter, and drop your reactions plus comments.
Top comments (3)
Nice walkthrough, thanks for writing it up. I had to work out the opposite yesterday for nearly identical reasons. I wanted to get the key from
dataset
and make it kebab-cased.I didn't consider adding a delimiter parameter or doing the reverse as you have. So I've tweaked my code after reading this.
Gist: gist.github.com/sarcoma/9df7d82bcc...
Credit where credit is due, I based my conversion off of this gist: gist.github.com/nblackburn/875e6ff...
Yeah RegExp is a great approach. I omitted that. I think I should add it. Thanks for sharing this.
No problem, Regex is so hard to read, go with whatever works for you. I was lucky enough to find a fairly decently tested Regex match and tweak it to suit my needs.
Thanks again, your post encouraged me to improve my scripts.