Home > OS >  Appended text is not updated according to CSV file changes
Appended text is not updated according to CSV file changes

Time:12-09

I use D3.js to import data from my CSV file into the project folder, using Live Server to create the HTML page produced in Visual Studio Code.

This piece of code is aimed at defining the text of a div:

                    enter.append("div")
                        .text(d => d.attackmomentum)
                        .style("color", "White");

The CSV file(./stackoverflow.csv) has this format:

id,attackmomentum
9832401,25

The value 25 is exactly the text value, in case it changes like for example to 90, the text would change from 25 to 90.

With that in mind, in the update script, I added .data(data,d=>d.attackmomentum):

                    let update_5 = select_5.selectAll(".matches")
                        .data(data,d=>d.id)
                        .data(data,d=>d.attackmomentum);

But when updating the attackmomentum column values in my CSV every 5 seconds according to the trigger I created, the value doesn't change according to what's in the file, it keeps the value from when I created the page.

What should I change to make this text update without needing to refresh the entire page?

Here is my full code (hiding only personal data for easy viewing).

<html>
    <head>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.1.1/d3.min.js"></script>
        <script src="https://cdn.jsdelivr.net/npm/d3-fetch@3"></script>
    </head>
    <body>
        <div class="grid games" id="jogos-stackoverflow">
        </div>
            <script id="script-da-caixa-de-selecao-suspensa-5">
                var select_5 = d3.select("#jogos-stackoverflow")
                .append("div")
                .attr("id","select-box-5")
                .style("width","100%")

                function valorparaiframe(iframevalue) {
                    let link = iframevalue;
                        return "https://........../"   iframevalue   "/";
                }

                async function update() {

                    let data = await d3.csv("./stackoverflow.csv");

                    let update_5 = select_5.selectAll(".matches")
                        .data(data,d=>d.id)
                        .data(data,d=>d.attackmomentum);
                    
                    update_5.exit().remove();

                    // Enter new divs:
                    const enter = update_5.enter()
                        .append("div")
                        .attr("class","matches");

                    // Append the sum
                    enter.append("div")
                        .text(d => d.attackmomentum)
                        .style("color", "White");
                    
                    // Append the children to entered divs:
                    enter.append("iframe")
                        .attr("src",d => valorparaiframe(d.id))
                        .style("width","100%")
                        .style("height","110");
                }
                
                update();
                    setInterval(update,5000);
            </script>
        </div>
    </body>
</html>

CodePudding user response:

The double .data is confusing me, but this is how I would do it.

You only updated the text of the new elements (after .enter() only the new elements are selected), and not of the existing elements. In my opinion, , using .join instead of .enter makes it much easier to separate the one-off logic with the updating logic. This gives the following code:

async function update() {
  let data = await d3.csv("./stackoverflow.csv");

  select_5.selectAll(".matches")
    .data(data, d => d.id)
    .join(
      enter => {
        // First append the containing div
        const divs = enter
          .append("div")
          .attr("class", "matches");
        
        // Append a div with the text and the iframe
        divs.append("div")
          .style("color", "white");
        divs.append("iframe")
          .attr("src", d => valorparaiframe(d.id))
          .style("width", "100%")
          .style("height", "110")
        
        // Return the divs matching ".matches" to be joined to the selection
        return divs;
      }
    )
    .select('div')
    .text(d => d => d.attackmomentum);
}
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

  • Related