Cascade-esq Notation in JavaScript?
Tags: javascript, dart, functional, healthydebate
Published: 2020-09-16 21:06:23

A little while ago I was going through the [Dart's Language Tour](https://dart.dev/guides/language/language-tour) and found this cool notation they got. They call it the `Cascade Notation`.

Here's a code example from the tour:
```
querySelector('#confirm') // Get an object.
  ..text = 'Confirm' // Use its members.
  ..classes.add('important')
  ..onClick.listen((e) => window.alert('Confirmed!'));
```

Which translates to:
```
var button = querySelector('#confirm');
button.text = 'Confirm';
button.classes.add('important');
button.onClick.listen((e) => window.alert('Confirmed!'));
```

Now, ain't that pretty? 😆

JavaScript's influence on Dart's syntax is quite evident. Its almost as if Dart is Javascript with nutella smeared all over it.
And as such, Dart has some feature over JavaScript which have got me drooling! 🤤


##My Problem

Its pretty common in JavaScript to programmatically build elements and populate them in some `parent` element. Like so:
```
let anchor = document.createElement('a');
anchor.href = data.link;
anchor.innerText = data.caption
anchor.classList.add(data.type)
parent.appendChild(anchor)
```
It has always bugged me to have to type that `anchor.someProp`. I wish we had something like that `Cascade Notation`, but alas, we don't. And _that's_ my problem.


##My Solution - Chain 'em all!

I will simply create a class that chains and have a `.build()` method that returns the element. Something like:
```
parent.appendChild(
  new Link()            // Returns a chainable builder
    .to(data.link)
    .text(data.caption)
    .type(data.type)
    .build()            // Finally, returns anchor element
)
```


##Now, how to implement?

[Chainable objects](https://en.wikipedia.org/wiki/Method_chaining) have been around for years and are pretty well known. And here's how I like to construct them.

First, I create a helping curry-ed function(check [Currying](https://medium.com/javascript-scene/curry-and-function-composition-2c208d774983)):
```
let chainer = (ctx) => (mutator) => (...args) => {
  mutator.apply(ctx, args)
  return ctx
}
```

Here,
1. `ctx` is the object that is chained upon
2. `mutator` is a function that is used to actually make changes to the ctx
3. `...args` are the arguments provided to the mutator

Then, I create the builder:
```
let Link = function () {
  let linker = chainer(this)
  
  let config = {
    to: "",
    text: "",
    type: "",
  }
  
  this.config = config
  this.to = linker((link) => {
    config.to = link
  })
  this.text = linker((text) => {
    config.text = text
  })
  this.type = linker((type) => {
    config.type = type
  })
  
  this.build = () => {
    let a = document.createElement("a")
    a.href = config.to
    a.innerText = config.text
    !!config.type && a.classList.add(config.type)
    return a
  }
}
```
Voila! we are done （︶^︶）


##Usage

We can use them ubiquitously, like literally smearing nutella. 😋
```
document.body.appendChild(
  new Link()
    .to("http://localhost")
    .text("home sweet home")
    .build()
)
```

##Wanna try?

{% jsfiddle https://jsfiddle.net/keogami/hufq9dcz/4/ result,js %}


##End Note

Yo reader! This was my way of trying to recreate the cascading syntax with JavaScript, if you got a better way... Share it with everyone!

Cheers~