Reputation: 15
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
Upvotes: 0
Views: 121
Reputation: 20944
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.
Upvotes: 1
Reputation: 2166
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');
})
Upvotes: 1