Code Within D3.JSON() Callback Is Not Executed

Code within d3.json() callback is not executed

The signature of d3.json has changed from D3 v4 to v5. It has been moved from the now deprecated module d3-request to the new d3-fetch module. As of v5 D3 uses the Fetch API in favor of the older XMLHttpRequest and has in turn adopted the use of Promises to handle those asynchronous requests.

The second argument to d3.json() no longer is the callback handling the request but an optional RequestInit object. d3.json() will now return a Promise you can handle in its .then() method.

Your code thus becomes:

d3.json("/trip_animate/tripData.geojson")
.then(function(data){
// Code from your callback goes here...
});

Error handling of the call has also changed with the introduction of the Fetch API. Versions prior to v5 used the first parameter of the callback passed to d3.json() to handle errors:

d3.json(url, function(error, data) { 
if (error) throw error;
// Normal handling beyond this point.
});

Since D3 v5 the promise returned by d3.json() will be rejected if an error is encountered. Hence, vanilla JS methods of handling those rejections can be applied:

  1. Pass a rejection handler as the second argument to .then(onFulfilled, onRejected).

  2. Use .catch(onRejected) to add a rejection handler to the promise.

Applying the second solution your code thus becomes

d3.json("/trip_animate/tripData.geojson")
.then(function(data) {
// Code from your callback goes here...
})
.catch(function(error) {
// Do some error handling.
});

Getting data using d3.json() is not working, while it works using JS async await.. Why?

According to the documentation, d3.json returns a promise, like fetch does, rather than accepting a callback. (Edit: Apparently in v4 it accepted a callback — that explains it.) If you use that promise, it works.

You can either use the promise via async/await as you did with fetch, or by using then and (since you're not returning the chain to anyone else who would handle it) catch.

async/await:

(async function() {  try {    const jsonResponse = await d3.json("https://raw.githubusercontent.com/FreeCodeCamp/ProjectReferenceData/master/GDP-data.json");
const data = jsonResponse.data; // array of dates and values const lowestVal = d3.min(data, d => d[1]); const highestVal = d3.max(data, d => d[1]);
console.log(lowestVal); console.log(highestVal); } catch(error) { console.log(error); }})();
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

Not sure if callback inside d3.json get called

The D3.js D3-fetch module uses the Fetch API to handle HTTP requests.

Therefore, to load and parse the JSON object, you will need to resolve the promise which was returned within the then() statement.

d3.json('some-path').then(response => {
console.log(response);
// handle the rest here
tmp(response);
});

Likewise, the anonymous function from tmp, within the renderWeather() method, should be called within the then() statement, since the rendering of the chart is dependent on the data returned by d3.json().

d3.json is not executed

Remove the type in the JSON function. JSON functions don't allow "accessors", only CSV and TSV functions allow them.

Thus, remove the type and do everything the type function does using a forEach inside your JSON function.

The first line of your JSON function has to be:

d3.json("omstandigheden.json", function(error, data) {

PS: If you are the one writing the JSON, you don't need the type function: just write the values as numbers, not strings.

d3.json method doesn't return my data array

TL;DR

d3.json (as well as d3.csv, d3.tsv etc) does not return the content of the loaded/parsed file. Instead of that, it returns an object related to the request in D3 v4 or lower, and a promise in D3 v5 or higher.

What does d3.json return? (v4 or lower)

d3.json is one of the alternatives to XMLHttpRequest provided by D3. According to the API, d3.json...

Returns a new request to get the JSON file at the specified url with the default mime type application/json.

... which, we can agree, is not particularly clear. Because of that, you probably thought that you could return the loaded data using var data = d3.json(url, callback), but that's incorrect. What d3.json returns is an object (not an array), associated with the request. Let's see it.

I have this JSON in a file:

{"foo": "42"}

What happens if we use d3.json the way you used it in your question? Click "run code snippet" to see:

var data = d3.json("https://api.npoint.io/5b22a0474c99d3049d2e", function() {});

console.log(data)
<script src="https://d3js.org/d3.v4.min.js"></script>

d3.json is not executed immediately but rather, later on

The callback function executes asynchronously after the browser retrieves the JSON file. Meanwhile, your for loop continues. That's the expected behavior. You'll want to defer execution until after all files have been retrieved. Depending on your preference and what libraries you have available, you could use any Promises library or jQuery $.Deferred. If you want to stick to the D3.js ecosystem, Mike Bostock has released the queue.js library exactly for this purpose. That library's README.md includes an example that's precisely your use case.

Code within d3.json() callback is not executed

The signature of d3.json has changed from D3 v4 to v5. It has been moved from the now deprecated module d3-request to the new d3-fetch module. As of v5 D3 uses the Fetch API in favor of the older XMLHttpRequest and has in turn adopted the use of Promises to handle those asynchronous requests.

The second argument to d3.json() no longer is the callback handling the request but an optional RequestInit object. d3.json() will now return a Promise you can handle in its .then() method.

Your code thus becomes:

d3.json("/trip_animate/tripData.geojson")
.then(function(data){
// Code from your callback goes here...
});

Error handling of the call has also changed with the introduction of the Fetch API. Versions prior to v5 used the first parameter of the callback passed to d3.json() to handle errors:

d3.json(url, function(error, data) { 
if (error) throw error;
// Normal handling beyond this point.
});

Since D3 v5 the promise returned by d3.json() will be rejected if an error is encountered. Hence, vanilla JS methods of handling those rejections can be applied:

  1. Pass a rejection handler as the second argument to .then(onFulfilled, onRejected).

  2. Use .catch(onRejected) to add a rejection handler to the promise.

Applying the second solution your code thus becomes

d3.json("/trip_animate/tripData.geojson")
.then(function(data) {
// Code from your callback goes here...
})
.catch(function(error) {
// Do some error handling.
});

Returning array from d3.json()

Besides the fact that your problem description is very terse, the problem seems to be your assumptions about what is returning what.

The function d3.json() is an asynchronous function that directly returns (with an undefined value I assume). Only when the data is received from the backend, the callback function you passed to it will be called. Obviously the context is different here and the return value of your callback will not automatically become the return value of d3.json (as this one has returned "long" before already).

What you want to do is probably something like:

    var jsondata;
d3.json(dataPath, function(dataFromServer) {
jsondata = dataFromServer;
}
console.log(jsondata);

Update 1:
Obviously, the above example is still not fully correct. The call to console.log() is made directly after the d3.json() returned. Thus, the server might not have sent the reply fully yet. Therefore, you can only access data when the callback is returned. Fixed example:

    var jsondata;

function doSomethingWithData() {
console.log(jsondata);
}

d3.json(dataPath, function(dataFromServer) {
jsondata = dataFromServer;
doSomethingWithData();
})

For a (somewhat stupid, but) working example see: http://jsfiddle.net/GhpBt/10/

Update 2:
The above example demonstrates in which order the code is executed but does not really deserve a price for most beautiful code. I myself would not use this "global" variable and simplify the above example to:

    function doSomethingWithData(jsondata) {
console.log(jsondata);
}

d3.json(dataPath, doSomethingWithData);

Note how doSomethingWithData is directly passed to d3.json in stead of calling it separately in an anonymous inner function.

Note: This is not a particular problem of d3.js. Basically, all javascript functions that are asynchronous are likely to behave in a similar way. If they return something, it will not be the return value of the passed callback.



Related Topics



Leave a reply



Submit