0

I'm trying to create a graph with D3, where the data needs to be loaded from a REST controller. Here is the code for the nodes I'm having problems with:

async function request(partNumber) {
    var response = await fetch(restURL + partNumber)
    var grafic = await response.text()
    return grafic
  }

nodes.selectAll("nodeSvg")
    .data(d => [d])
    .enter()
    .append("g")
    .attr("transform", function(d) { 
        return "translate(" + [offsetX + d.x * scale + svgOffsetX, offsetY + d.y * scale + svgOffsetY] + ") scale(0.1 0.1)"; })
    .html(async (d) => {
        if (d.partNumber === "") {
            return "";
        }
        return await request(d.partNumber);
    });

As you can see I create to stream for the data. Each of the data entrys has a partNumber which I need to get an HTML string from the RestApi. This string is an SVG string which if hard coded produces a picture as node. But if I don't hardcode it and request it (which actually gives me a string if I set a breakpoint) the nodes are not created. How can I resolve this?

Thanks in advance!

EDIT: I'm using D3v5 which added Promises, but I'm not sure if and how this can help me

EDIT2: Made the question more clear

EDIT3: I found a solution which alows me to add the svgs after loading the rest of the graph, which is better if there are a lot of svgs to load from the REST Api. Here si how I did it:

async function request(partNumber) {
    if (partNumber !== "") {
        var response = await fetch(restURL + partNumber)
        return await response.text()
    }
  }

drawing.nodes.forEach((d) => {
    if (d.partNumber === "") {
        d.graphic = "";
    }
    request(d.partNumber).then((e) => {
        d.graphic = e;
        nodes.selectAll("nodeSvg")
            .data(d => [d])
            .enter()
            .append("g")
            .attr("transform", function(d) {
                return translateNode(d); })
            .html((d) => {
                return d.graphic
            });
    });

})

I just moved the part that creates the nodes into the ".then()" part. As it turns out D3 just updates changed values instead of redrawing it again and again as it is in a loop.

Anyways: Thank you Mikkel for your answer!

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
  • Does this answer your question? [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – zero298 Jan 07 '20 at 16:12
  • I fear I doesn't. As you can see I already use await to solve this. The problem is that D3 doesnt show the nodes (The return string from the request function is a svg) Maybe my question wasnt exactly clear on this point. I will edit my question – Mic At4Soft Jan 07 '20 at 16:18

1 Answers1

1

Welcome to Stack Overflow.

There are a couple of things going on here that might not be ideal.

1) Your request function does 2 awaits in succession, which isn't great - I would recommend using the axios library (rather than fetch), which will return you data without the need for a .then() or await.

2) D3 is a declarative language, and works a little differently. You pass in a function to html(), which is probably ok, the declaration of it looks alright, and it may well work. I would, however, question the need to do an API call for each and every item on your page/drawing - performance won't be great, so I wpuld think about iterating over your incoming data, and assembling all of the part information before you start rendering.

This will allow you a much cleaner user experience, you will be able to display a spinner while you are loading data, and once you have it, the rendering will be quick (and not jerky)

It may be that fixing 1) solves the problem, but I would recommend dealing with issue 2) as well. Good luck!

Mikkel
  • 7,693
  • 3
  • 17
  • 31
  • I don't think using a pretty massive unmaintained library (axios) over a lean built-in browser API is necessarily a good recommendation. I don't want to say you're outright wrong, it's just just subjective and not an accepted best practice, and detracts from the important part of your answer. So I feel this answer would be a bit better without that point! – Evert Jan 07 '20 at 23:39
  • I wouldn't call it unmaintained. 0.19.1 was release 2 days ago, and if you look at the recent contributions here https://github.com/axios/axios/graphs/contributors you will see there is recent activity. – Mikkel Jan 09 '20 at 09:19
  • I used your second approach and it worked out fine! Thank you. But now I actually found a way to load the svgs afterwards, which is better if there are tons of them. I will edit my question and show the answer there. – Mic At4Soft Jan 10 '20 at 09:20