So I'm developing a webpage and I want to display the value of a variable in a part of it. The variable is being manipulated by many functions and I want the displayed value as the current value of the variable. How exactly do I do that?
By the way here's the code. Even if the functions manipulate the variable, it still shows "1"
var cpc = 1;
document.getElementById("curcpc").innerHTML = cpc;
There's nothing that will automatically update the DOM for you when the variable changes. (There are lots of libraries or frameworks that will update the DOM for you if you follow their rules for how you change it, but nothing that will do it completely automatically.)
There are a few ways to do it.
One simple way to fix that is to not make it a simple variable. Instead, make setting it something that requires a function call, and have the function call update both the variable and the DOM.
You might make updating it an explicit function call (explicit is usually good!), or you could make it an accessor property with a getter and setter. The upside is you're not going to miss any updates. The downside is it's a function call every time you get or set the "variable"'s value (though with an accessor it doesn't look like one).
Here's a really basic version of that using an accessor:
const data = (() => {
let cpc;
const curcpc = document.getElementById("curcpc");
return {
get cpc() {
return cpc; // Returns the value of the variable
// declared above
},
set cpc(newValue) {
cpc = newValue; // Updates the var above
curcpc.innerHTML = cpc;
}
};
})();
data.cpc = 0;
// Some place updating it
document.getElementById("btn-add").addEventListener("click", () => {
++data.cpc;
});
// Some other place updating it
document.getElementById("btn-subtract").addEventListener("click", () => {
--data.cpc;
});
<div id="curcpc"></div>
<input type="button" value="+" id="btn-add">
<input type="button" value="−" id="btn-subtract">
But here's a version that's more efficient, not updating the display until the next time the browser is about to paint the page (by asking for a callback via requestAnimationFrame
), which means repeated updates that wouldn't have been visible don't get made unnecessarily:
const data = (() => {
let cpc;
const curcpc = document.getElementById("curcpc");
let rAFHandle = 0;
const updateCurCpc = () => {
curcpc.innerHTML = cpc;
rAFHandle = 0;
};
return {
get cpc() {
return cpc; // Returns the value of the variable
// declared above
},
set cpc(newValue) {
cpc = newValue;
if (!rAFHandle) {
rAFHandle = requestAnimationFrame(updateCurCpc);
}
}
};
})();
data.cpc = 0;
// Some place updating it
document.getElementById("btn-add").addEventListener("click", () => {
++data.cpc;
});
// Some other place updating it
document.getElementById("btn-subtract").addEventListener("click", () => {
--data.cpc;
});
<div id="curcpc"></div>
<input type="button" value="+" id="btn-add">
<input type="button" value="−" id="btn-subtract">
Another way is to wrap any event handlers and such in a function that remembers the old value and updates the DOM after the event handler is done if the value has changed. This has the advantage that reading/writing the variable is a simple read/write, not a function call, but adds the cost of doing the comparison after each event handler completes and the possibility of adding a hanlder you forget to wrap.
Here's a basic example of that (without requestAnimationFrame
, it doesn't add much in this case):
let cpc = 0;
const curcpc = document.getElementById("curcpc");
curcpc.innerHTML = cpc;
const wrapHandler = (handler) => {
// Return a non-arrow function (we want `this` set by the caller)
return function(...args) {
try {
const result = handler.apply(this, args);
curcpc.innerHTML = cpc;
return result;
} catch (e) {
curcpc.innerHTML = cpc;
throw e;
}
};
};
// Some place updating it
document.getElementById("btn-add").addEventListener("click", wrapHandler(() => {
++cpc;
}));
// Some other place updating it
document.getElementById("btn-subtract").addEventListener("click", wrapHandler(() => {
--cpc;
}));
<div id="curcpc"></div>
<input type="button" value="+" id="btn-add">
<input type="button" value="−" id="btn-subtract">