D3 Method Chaining
D3 uses a convention called method chaining. Basically what it means is that when you call a method on an object, it performs the method and returns an object. Since the method on an object returns an object, another method can be called without having to explicitly reference an object again. It's a bit hard to describe in text, let's look at an example.
This animation demonstrates the results of each call in the method chain. In contrast to the last lab, all operations are on one line and no intermediate vars were required.select("body") returns a selection of the body. append("h1") returns a selection of the newly created h1. Finally text("Hi there") sets the text of the h1 selection. From here out, most D3 calls will be method chains.
It is quite common to see method chains that are five or more calls deep. With longer chains I've found that the code is easier to read if each new method call is on it's own line. Below is the same example using the one method call per line style.
d3.select("body") .append("h1") .text("Hi there");
Append breaks the chain
append is a bit of a special case for method chaining because it creates a new element and returns a selection to it. In most cases methods that operate on an object will return the same object being operated on. Imagine if you wanted to add two "h1" to the bottom of the body. With what we have covered so far, it isn't possible to do this with one method chain. That's because the first append will return the new "h1" selection instead of the original "body" selection. This results in a nested "h1".
The above code produces the document structure below
<body> <h1> <h1> </h1> </h1> </body>
In this case an intermediary variable is required. One solution looks like this.
var body = d3.select("body"); body.append("h1"); body.append("h1");
Many D3 objects are configured using method calls. Method chaining allows this configuation to happen in a compact way. Code like the below is commonplace in D3 code.
var configuredObject = aD3_constructor() .setting1("someValue") .setting2("someOtherValue");
This code above is a fake example, but in code like this, both setting1 and setting2 perform their change to the object and return that object. The main win is compact code because configureObject only has to be mentioned once to configure it.
Calling append() on a selection returns a selection to the newly created element. True/False. Calling text() on a selection modifies the text of the selection and returns the same selection. True/False. var body = d3.select("body"); var h1 = body.append("h1"); h1.text("Hello"); Is this a method chain? (Yes/No)
Things to do
- Use a method chain to create a ul element in the document.
- Using a selection to the ul element, append an li element with the text "Method Chaining". Do this using a method chain.
- Do this one more time this time with the text "I get the idea now"
- For fun, construct a chain with 5 or more calls in it.