1

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.

7
  • 1
    Why does it work only once? It looks like ourButtonStyle.property("foo").value("bar").property("baz").value("qux") should work just fine. (Aside: stuff like ourButtonStyle.property("foo").property("bar").value("baz") is also possible, but confusing, which shows that this might not be the best API design.) Commented May 31, 2020 at 12:12
  • Just saying: there's absolutely nothing wrong with creating new objects! Commented May 31, 2020 at 12:15
  • @Thomas I get the error: "Uncaught TypeError: ourButtonStyle.property is not a function" after executing the chain once. MRA: codepen.io/melvinidema/pen/wvKVNba?editors=0011 Commented May 31, 2020 at 12:16
  • @Bergi I agree, but the point of why I'm trying to do this. (instead of just calling: node.style.property = value - which is way more minimalistic) is to practice method chaining and creating Fluent API's. And creating a new object every time you want to change a style isn't really practical IMO. Commented May 31, 2020 at 12:18
  • @MelvinIdema In an ideal fluent API, all objects are immutable, and each method call will return a new instance. (I'm not saying that you should have to call new FStyle(…) multiple times, I'm only saying that you could easily use multiple objects in the chain). Commented May 31, 2020 at 12:24

1 Answer 1

2

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;
}
Sign up to request clarification or add additional context in comments.

3 Comments

This was a huge "Eureka" moment right here. You're absolutely right! Weird how this just completely went over my head. Sadly -and weirdly- though, it doesn't seem to solve the problem... I still get the typeError. But checking the type of ourButtonStyle.property it says: function. Even after executing it once. The console literally logs: Typeof ourButtonStyle.property: function and immediatly after: typeError ourButtonStyle.property is not a function
Facepalm, I didn't see you changed the value as well. Thank you so much! I think it's time for a break haha. Solved! Do you perhaps have a suggestion to chain functions without creating a new object? Something like: changeStyle(node).property("border-color").value("red");
@MelvinIdema Glad, you got it working! As for your question about chaining without creating directly a new object, maybe something like this could help you: function changeStyle(node){ return new FStyle(node)}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.