Search code examples
javascriptecmascript-6fluentchaining

Is there a way to chain Javascript functions without creating a new object?


Imagine we have a Button element

const ourButton = document.getElementById("#theButton");

And we want a fluent API to change the styles of this button without creating a new object, so chain a function like this:

style(ourButton).property("padding").value("32px");

Is this possible? I can't seem to figure out how to create this behaviour. I tried building a Fluent API "the conventional way" by creating a constructor function like this:

var FStyle = function(node) {
  this.node = node;
}

FStyle.prototype.property = function(property) {
  this.property = property;
  return this;
}

FStyle.prototype.value = function(value) {
  this.value = value;
  this.node.style[this.property] = this.value;
  return this;
}

and using it by constructing a new object:

const ourButtonStyle = new FStyle(ourButton);
ourButtonStyle.property("padding").value("64px");

Which works, once. If I would like to add a new style I have to create a whole new object. Why is this?

TL;DR: For learning purposes I'm trying to chain functions but don't understand it fully enough to understand the above behaviour. Returning this in a normal function to chain other functions to it won't do the job either. In the end I would like to "pipe" the result of a function to an other function.


Solution

  • Although not easily seen, the issue here is the namings!

    You are creating a prototype function called property and then essentially you overwrite this function with the value you got from the function call. Check the comments in the code below.

    FStyle.prototype.property = function(property) {
      // at this point "ourButtonStyle.property" is a function
      this.property = property;
      // here "ourButtonStyle.property" is a string 
      return this;
    }
    

    An easy fix would be to rename these with something slightly deifferent

    var FStyle = function(node) {
      this.node = node;
    }
    
    FStyle.prototype.property = function(prop) {
      this.prop = prop;
      return this;
    }
    
    FStyle.prototype.value = function(val) {
      this.val = val;
      this.node.style[this.prop] = this.val;
      return this;
    }