简体   繁体   中英

How do I only render the updated stat - websockets

right now the entire div re-renders, but I am searching for a way to only re-render the updated statistic

these are parts of what I have now

updatestats.js

document.querySelector("#submit").addEventListener("click", function (e) {
let country = document.querySelector("#country").value
let numberCases = document.querySelector("#number").value

fetch(base_url + "/api/v1/stats/updatestats", {
    method: "put",
    headers: {
        "Content-Type": "application/json"
    },
    body: JSON.stringify({
        "country": country,
        "numberCases": numberCases
    })
}).catch(err => {
    console.log(err);
})

primus.write({ "action": "update" })

stats.js

 primus.on("data", (json) => {
    if (json.action === "update") {
        document.querySelector("#overview").innerHTML = ""
        appendInfo()
    }
})

function appendInfo() {
    fetch(base_url + "/api/v1/stats", {
        method: "get",
        headers: {
            'Content-Type': 'application/json'
        },
    }).then(response => {
        return response.json();
    }).then(json => {
        json.data.stats.forEach(stat => {
            let country = stat.country
            let numberCases = stat.numberCases
            let p = document.createElement('p')
            let text = document.createTextNode(`${country}:   ${numberCases}`)
            p.appendChild(text)
            let overview = document.querySelector("#overview")
            overview.appendChild(p)
        })
    }).catch(err => {
        console.log(err);
    })
}


window.onload = appendInfo();

stats.pug

body
h1 Cases by country
div#overview

So if I only update the country Belgium I only want that statistic to be changed. Now everything seems to reload

What I meant with my suggestion is to keep te communication of data between client and server strictly in the sockets. Meaning when one user updates 1 value on their end, that value will be send to the server and stored. After the server finished storing the value, that same value will be sent to all other clients. This way you only send and receive the parts that have been changed without having to download everything on every change.

I might not be able to write the code exactly as it should be as I have limited experience with Primus.js and know little about your backend.

But I would think that your frontend part would look something like this. In the example below I've removed the fetch function from the click event. Instead send the changed data to the server which should handle those expensive tasks.

const countryElement = document.querySelector("#country");
const numberCasesElement = document.querySelector("#number");
const submitButton = document.querySelector("#submit");

submitButton.addEventListener("click", function (e) {

  let data = {
    action: 'update',
    country: countryElement.value,
    numberCases: numberCasesElement.value
  };

  primus.write(data);

});

Now the server should get a message that one of the clients has updated some of the data. And should do something with that data, like storing it and letting the other clients know that this piece of data has been updated.

primus.on('data', data => {
  const { action } = data;
  if (action === 'update') {

    // Function that saves the data that the socket received.
    // saveData(data) for example.

    // Send changed data to all clients.
    primus.write(data);

  }
});

The server should now have stored the changes and broadcasted the change to all other clients. Now you yourself and other will receive the data that has been changed and can now render it. So back to the frontend. We do the same trick as on the server by listening for the data event and check the action in the data object to figure out what to do.

You'll need a way to figure out how to target the elements which you want to change, you could do this by having id attributes on your elements that correspond with the data. So for example you want to change the 'Belgium' paragraph then it would come in handy if there is a way to recognize it. I won't go into that too much but just create something simple which might do the trick.

In the HTML example below I've given the paragraph an id. This id is the same as the country value that you want to update. This is a unique identifier to find the element that you want to update. Or even create if it is not there.

The JavaScript example after that receives the data from the server through the sockets and checks the action. This is the same data that we send to the server, but only now when everybody received we do something with it.

I've written a function that will update the data in your HTML. It will check for an element with the id that matches the country and updates the textContent property accordingly. This is almost the same as using document.createTextNode but with less steps.

<div id="overview">
  <p id="Belgium">Belgium: 120</p>
</div>
const overview = document.querySelector("#overview");

primus.on('data', data => {
  const { action } = data;
  if (action === 'update') {
    updateInfo(data);
  }
});

function updateInfo(data) {
  const { country, numberCases } = data;

  // Select existing element with country data.
  const countryElement = overview.querySelector(`#${country}`);

  // Check if the element is already there, if not, then create it.
  // Otherwise update the values.
  if (countryElement === null) {
    const paragraph = document.createElement('p');
    paragraph.id = country;
    paragraph.textContent = `${country}: ${numberCases}`;
    overview.append(paragraph);
  } else {
    countryElement.textContent = `${country}: ${numberCases}`;
  }
}

I hope that this is what you are looking for and / or is helpful for what you are trying to create. I want to say again that this is an example of how it could work and has not been tested on my end.

If you have any questions or I have been unclear, then please don't hesitate to ask.

To elaborate @EmielZuurbier's suggestion in the comment, please try the following code.

//Client-side

primus.emit('data',data);

primus.on("dataUpdated", (json) => {

});

//Server-side

primus.on('data',data =>{

//process it here and then
//send it out again


primus.emit('dataUpdated','the data you want to send to the front end');

})

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM