A little while ago I was going through the Dart's 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 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):
let chainer = (ctx) => (mutator) => (...args) => {
mutator.apply(ctx, args)
return ctx
}
Here,
-
ctx
is the object that is chained upon -
mutator
is a function that is used to actually make changes to the ctx -
...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?
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~
Top comments (0)