Can you specify the third argument sent to the listener?

Recently I delved into exploring the capabilities of the d3 framework. One thing that caught my attention was the presence of a third parameter in the event listener for v3. Despite always being 0, I couldn't find any explanation on its intended purpose.

According to the documentation:

The specified listener is invoked in the same manner as other operator functions, being passed the current datum d and index i, with the this context as the current DOM element.

This leaves me questioning the significance of this mysterious third parameter.


In the code snippet below, you'll notice that when clicking on any of the rectangles, three parameters are passed to the function f:

var svg = d3.select("body").append("svg")

function f(d, idx, whoami) {
    console.log('I am the data:\t' + d);
    console.log('I am the index:\t' + idx);
    console.log('But who am i?\t' + whoami);
    console.log('Length:' + arguments.length);
    console.log(arguments);
}

var data = ['A', 'B', 'C'];

svg.selectAll('rect')
  .data(data)
    .enter()
    .append('rect')
    .attr("x", 0)
    .attr("y", function(el, i) {return i * 40;})
    .attr("width", 100)
    .attr("height", 40)
    .on("click", f);
rect {
  fill: #333;
  opacity: 0.3;
  stroke: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>

Answer №1

There is a hidden feature that remains undocumented. If you explore the code implementation of selection.on() in version 3.5.17, you will discover that it utilizes selection.each() internally to connect the listener to each node within the selected group.

return this.each(d3_selection_on(type, listener, capture));

Furthermore, the internal function d3_selection_on leads to onAdd for adding listeners, and this reference is passed as the callback to .each(). Therefore, .each() executes onAdd for every individual node in the current selection. Meanwhile, onAdd encapsulates the arguments from the .each() call by storing them in the listener's context:

function d3_selection_on(type, listener, capture) {

  /* ... */

  function onAdd() {
    var l = wrap(listener, d3_array(arguments));  // wrap points to d3_selection_onListener
    /* ... */
  }

  /* ... */

function d3_selection_onListener(listener, argumentz) {
  return function(e) {
    /* ... */
    argumentz[0] = this.__data__;                 // Set the latest datum as the first argument
    try {
      listener.apply(this, argumentz);            // Pass arguments from closure to the listener
    } finally {
      d3.event = o;
    }
  };
}

Upon examining the implementation of selection.each(), it becomes evident that not only two arguments—mentioned in the official documentation—are provided to the callback but rather three arguments:

if (node = group[i]) callback(node, i, j);

The third argument j represents the index of the group. In cases where grouping is absent, this argument always holds the value 0.

By modifying your demonstration, it's possible to showcase how establishing a grouped selection impacts the value assigned to this third argument. The following snippet replicates your three rectangles while organizing them into separate <g> elements with their own data binding to establish a form of grouping.

var svg = d3.select("body").append("svg")

function f(d, idx, whoami) {
    console.log('I am the data:\t' + d);
    console.log('I am the index:\t' + idx);
    console.log('But who am i?\t' + whoami);
    console.log('Length:' + arguments.length);
    console.log(arguments);
}

var data = [['A', 'B', 'C'], ['a', 'b', 'c']];

svg.selectAll('g')
  .data(data)
  .enter().append('g')
  .selectAll('rect')
  .data(d => d)
  .enter().append('rect')
    .attr("x", function(el, i, j) {return j * 110;})
    .attr("y", function(el, i) {return i * 40;})
    .attr("width", 100)
    .attr("height", 40)
    .on("click", f, true);
rect {
  fill: #333;
  opacity: 0.3;
  stroke: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.js"></script>

This aspect remains entirely unmentioned in the official documentation for both .each() and .on().

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Just starting out with JS, curious if it's possible to transform these circles into diamonds instead

My goal is to transform this animated field of blinking circles into rectangles or diamonds, whichever is easier. Link: http://jsfiddle.net/Jksb5/1/ HTML <canvas id="pixie"></canvas> JS var WIDTH; var HEIGHT; var canvas; var con; var g; va ...

Traversing an array in Javascript by iterating through its elements

So I have an array called var myImages = [];. After pushing items into it and using console.log(), I see the following: ["01_img"] ["02_img"] ["03_img"] ["04_img"] ["05_img"] When I click on something, I want to change the background of a div to display ...

Issue with redirect using Node.js promise

I’ve created a settings page where users can add and remove filters. To handle the deletion process, I’ve implemented this jQuery function: $('#delete-filter').click(function (e) { var filtername = $('#filter-list').val(); ...

Styling sub-table titles in jQuery jTable with proper indentation

I am currently implementing jquery.jtable, where I have rows that invoke the openChildTable method in the jquery.jtable.js file. I'm attempting to figure out a way to indent the heading of the child table. Below is the code snippet responsible for cr ...

How can I update the color of a list item when it is clicked within a foreach loop using knockout js?

Currently, I am encountering an issue with changing the color when a user clicks on a list item using the latest version of knockout js. My goal is to change the color of a list item when it is clicked and maintain that color until another item is clicked, ...

Utilizing a variable name as an object key in TypeScript

Can this be achieved? static readonly statusMapping: { [key in UploadStatus]: PopupMessageStatus } = { UploadStatus.COMPLETED : PopupMessageStatus.COMPLETED } UploadStatus is an enum with numeric values, where UploadStatus.COMPLETED = 0 p ...

Encountering an error when trying to destructure a property of null

The concept of destructuring is fascinating, but I have been facing some challenges when trying to destructure nested objects. Consider the following code snippet: const { credit: { amount }, } = userProfile This can be risky because if the &ap ...

An unusual occurrence with the setTimeOut function within a for loop was observed

When attempting to log numbers at specific intervals on the console, I encountered an unexpected issue. Instead of logging each number after a set interval, all numbers are logged out simultaneously. I've experimented with two different approaches to ...

Webpack has made Rails .js.erb templates obsolete

Recently, I migrated my Rails application to use WebPack for handling assets, and it has been operating smoothly. However, I encountered an issue with JS templates located in my views directory (*.js.erb) that require jQuery. Since jQuery is included in my ...

Build a Node.js application with Express to host static files

I am attempting to provide my static files "web.html" and "mobile.html", but I want them to be served only if the user is accessing from a web or mobile device. After some research, I came up with this code: var express = require('express'); va ...

Update data in the datatables using values from an array list

Currently, I have two HTML files where I am loading data using JSON and then applying jQuery datatables to them. Now, I need to refresh the data with new parameters. For example: JSON: [ {"name":"jon","sales":"100","set":"SET1"}, {"name":"charlie","sale ...

Trouble with activating dropdown toggle feature in Bootstrap 5

I recently upgraded to Bootstrap 5 and now my code is not functioning properly. <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarCollapse" aria- controls="navbarCollaps ...

Is there a way to mock a keycloak API call for testing purposes during local development?

At my company, we utilize Keycloak for authentication integrated with LDAP to fetch a user object filled with corporate data. However, while working remotely from home, the need to authenticate on our corporate server every time I reload the app has become ...

PHP and AJAX: Combining Powers to Fetch Data

Greetings. I am currently in the process of creating a WordPress plugin that will manually send an email containing WooCommerce Order details to a specified supplier's email address. I am facing a challenge in understanding how to load data when a use ...

Merge a dropdown menu with an alphabetically arranged list that is interactive with clickable options

I am still learning HTML and Javascript but I'm doing my best. Currently, I am facing a challenge where I need to create a button that, when clicked, opens a dropdown menu containing a table of data. The user should then be able to select a number fr ...

Elevate the index of the name attribute for an input field within a dynamically generated form

In my scenario, I have created a form that includes indexed input fields for username and level: <form> <table> <tr class="trToClone"> <td> <label>Username:</label> <input type="text" name="usernam ...

How to trigger an Angular JS route without loading a view

Could someone help me with calling the /auth/logout url to get redirected after a session is deleted? app.config(['$routeProvider',function($routeProvider) { $routeProvider .when('/auth/logout',{ controller:'AuthLo ...

Tips on updating a specific value within an element stored in an array

I'm currently in the process of setting up a table where each row contains unique values. Using a for loop, I am able to generate these rows and store them in an array. Now, my question arises when I consider modifying a particular value with the id " ...

Identifying fluctuations in unprocessed data

Currently in the process of developing a web application that serves as a dashboard for monitoring storage tank levels. It gathers data from various sensors inside tanks and saves this information in a database. The tool is created using express / node.js. ...

Refreshing the page in VueJs does not trigger the axios function

I've encountered an issue with my VueJs app after purchasing the Vuexy template from ThemeForest. I created a new component called CountryTable.vue, and while it works initially, it fails to display data when I refresh the page. It only shows data whe ...