DEV Community

Caleb Adepitan
Caleb Adepitan

Posted on • Edited on

Object properties: Convert delimited strings to camelCase in JavaScript

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)
  )
}
Enter fullscreen mode Exit fullscreen mode

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())
}
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

We can now get our property value.

const value = HTMLElement.dataset[newName]
Enter fullscreen mode Exit fullscreen mode

Note: HTMLElement.dataset is not an object literal. It is a DOMStringMap Object.

interface HTMLElement {
  dataset: DOMStringMap;
}
Enter fullscreen mode Exit fullscreen mode

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)

Collapse
 
__orderandchaos profile image
Order & Chaos Creative • Edited

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.

const camelCaseToDelimitedString = (string, delimiter = '-') => 
    string.replace(/([a-z0-9]|(?<!^)(?=[A-Z]))([A-Z])/g, '$1'+delimiter+'$2').toLowerCase();

const delimitedStringToCamelCase = (string, delimiter = '-') =>
    string.replace(new RegExp(delimiter + '([a-z])', 'g'), (m, c) => c.toUpperCase());

/**
 * Examples
 */
console.log(camelCaseToDelimitedString('helloWorld'));
console.log(camelCaseToDelimitedString('helloWorld', '_'));
console.log(camelCaseToDelimitedString('HelloWorld'));
console.log(camelCaseToDelimitedString('HelloWorld', '_'));
console.log(delimitedStringToCamelCase('hello-world'));
console.log(delimitedStringToCamelCase('hello, world', ', '));

Gist: gist.github.com/sarcoma/9df7d82bcc...

Credit where credit is due, I based my conversion off of this gist: gist.github.com/nblackburn/875e6ff...

Collapse
 
calebpitan profile image
Caleb Adepitan

Yeah RegExp is a great approach. I omitted that. I think I should add it. Thanks for sharing this.

Collapse
 
__orderandchaos profile image
Order & Chaos Creative

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.