Issue
Context: I have a web page that allows the user to add assets by clicking on a button. When the user presses this button, the main goal is that the Quota get's divided by the number of assets added (so that the quota % is distributed equally)
Problem: Everything is working as planned, however, I would want to update the values of the Quota as new assets are added. What I want is the following: we start with 1 asset which takes 100%. Then, by adding a new asset, we would have 2 assets, both with 50%. Adding a 3rd asset would update the Quota values to 33.33% for all 3 assets, etc. The only way I can draw the graph is if I delete all the Potential Loss values (literally delete the 0 that is set to each row), which then updates to the correct Quota values. As of now, the code With 3 assets added will retrieve 100% for the 1st, 50% for the 2nd, and 33.33% for the 3rd asset (in this situation, all should change their quotas to 33.33% automatically).
Question: Is there a way to automatically update the Quota values as the user presses the Add Asset button or Draw Graph button?
Failed Implementations: I was thinking of taking the latest quota index value and then update the previous indices with this key values of quota so that whenever the user presses "draw graph", the previous quota values are updated and I tried doing that with Object.keys
, but this will create conflict with the data since changing the values of one, will change the values of the other DOM elements (since they share the same index) - meaning if we change the name of the last "NEW STOCK" added, this will change the others as well.
Thank you in advance!
Original JS
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://www.gstatic.com/charts/loader.js"></script>
</head>
<body style="background-color:#DFCFBE">
<div class="row">
<div class="column left">
<form id=" form">
<div class="tr">
<div class="td">Asset </div>
<div class="td">Quota % </div>
<div class="td">Potencial Loss % </div>
</div>
<div class="tr" data-type="wrapper" data-index="1">
<div class="td" data-type="field_div"><input type="text" size="5" value="NEW STOCK" class="stock"
onchange="drawChart();" /> </div>
<div class="td"><input type="number" min="0" max="100" value="100" class="quota"
onchange="drawChart();" /> </div>
<div class="td"><input type="number" min="0" max="100" value="0" class="perda" />
</div>
</div>
<p onload="addNumAtivo();" id="indexSum">Number of Assets: 1</p>
<p onload="addNumAtivo();" id="indexQuota">Quota per asset: </p>
<p id="indexLoss">Total Loss:</p>
<button class="button2" type="button" onclick="addStock(event), addNumAtivo();">Add
Asset</button>
<button class="button1" type="button" onclick="drawChart();">Draw Graph</button>
</form>
</div>
</div>
<div class="column right" style="position:relative;width:70%">
<div class=" piechart" id="piechart" style="position:absolute;right:0px;top:0px;width: 900; height: 590px;">
</div>
</div>
</body>
<script>
//Define variables
let perda; //This value is calculated on line 154
let indexSum = 1;
let valuePercentage = 100; //This value percentage is essentially the "Quota". This value will be 100% divided by the amount of indexSum (essentialy, divided by ativo1, ativo2, ativo3... ativo(i))
let indexSumRatio = 1;
let numQuota = 100;
let numAtivo = 1;
document.getElementById("indexSum").innerHTML = `Number of Assets: ${numAtivo++}`;
document.getElementById("indexQuota").innerHTML = `Quota per asset: ${valuePercentage}%`;
//Functions that will increase the number of Assets and change the quota % as the user adds new assets (Add Stock) on the HTML
function addNumAtivo() {
document.getElementById("indexSum").innerHTML = `Number of Assets: ${numAtivo++}`;
document.getElementById("indexQuota").innerHTML = `Quota per asset: ${valuePercentage}%`;
}
document.getElementsByClassName("button2").onclick = numAtivo;
document.getElementsByClassName("button2").onclick = valuePercentage;
////////////////////////////////////////////////////////////////////////////////////
//Load google chart graphs
google.charts.load("current", {
packages: ["corechart"]
});
google.charts.setOnLoadCallback(drawChart);
// Function that will add new "Ativo", a new "Quota%" and a new "Perda potencial%" as the user presses the button "Add Stock".
function addStock(event) {
// find the last Wrapper [data-set="wrapper"]
let lastWrapper = event.currentTarget.form.querySelector(`[data-type="wrapper"]:last-of-type`);
// get the index of the last Wrapper
let lastIndex = parseInt(lastWrapper.dataset.index);
//clone the wrapper
let clonerNode = lastWrapper.cloneNode(true);
//change index of cloner Wrapper
indexSum = clonerNode.dataset.index = parseInt(lastIndex) + 1;
//changes values;
clonerNode.querySelector(`.stock`).value = "NEW STOCK";
valuePercentage = clonerNode.querySelector(`.quota`).value = (100 / indexSum);
//append clonernode after lastWrapper
lastWrapper.insertAdjacentElement('afterend', clonerNode);
indexSumRatio = 1 / indexSum;
console.log(`This is the sum of the indices (number of stocks = indexSum) ${indexSum}`)
console.log(`This is the valuePercentage (quota) ${valuePercentage}`)
console.log(`This is the indexSumRatio (perda potencial Ratio) ${indexSumRatio}`)
}
////////////////////////////////////////////////////////////////////////////////////
//Function that will be passed by the "Draw Graph" button so that everytime the user clicks the button, it takes the new input values and updates the pie chart
function drawChart() {
let slices = []; //the amount of "slices" on the pie chart is also the number of indices added
for (let i = 1; i <= indexSum; i++) { //i <= slices.length
slices.push({
ativo: document.querySelector(`div [data-type="wrapper"][data-index="${i}"] .stock`).value,
quota: parseFloat(document.querySelector(`div [data-type="wrapper"][data-index="${i}"] .quota`).value)
})
}
//Calculate the Loss (Perda) - this value is essentially the total amount of loss that the assets have taken when the user changes the "Perda potencial". This value is calculated by doing quota (valuePercentage) - perda potencial (perda) * (1/amount of assets)
document.querySelector(".row").addEventListener("input", function (e) {
const tgt = e.target;
if (tgt.classList.contains("perda")) {
perda = Number(tgt.closest(".tr").querySelector(".quota").value =
valuePercentage - tgt.value * indexSumRatio)
}
});
let sum = 0.0;
for (let i = 0; i < slices.length; i++) {
sum += slices[i].quota;
};
perda = 100.0 - sum;
console.log(`This is the Total Loss (perda) ${perda}`)
document.getElementById("indexLoss").innerHTML = `Total Loss: ${perda}%`;
document.getElementsByClassName("button2").onclick = perda;
//Create data table with input data
var data = new google.visualization.DataTable();
data.addColumn("string", "Ativo");
data.addColumn("number", "Quota");
data.addRows([
...slices.map(slice => ([slice.ativo, slice.quota])), ["Loss", perda],
]);
//Styling
let options = {
'legend': 'right',
pieHole: 0.3,
pieSliceText: 'value',
is3D: true,
colors: ['#FBB117', '#6AA121', '#728FCE', '#4863A0', '#7D0552', '#FF0000'],
backgroundColor: '#DFCFBE',
chartArea: {
left: 50,
right: 50,
top: 70
}
};
var chart = new google.visualization.PieChart(
document.getElementById("piechart")
);
chart.draw(data, options);
}
//adicionar for loop para ter o valor da quota personalizada e fazer os calculos da perda consoante esse valor
////////////////////////////////////////////////////////////////////////////////////
//RESOURCES
//https://www.youtube.com/watch?v=y17RuWkWdn8&ab_channel=WebDevSimplified
// usar este video para criar uma função que faça append de um novo div com atributos semelhantes aos outros para permitir ao usuario adicionar novos ativos com o cloque de um butao
//isEmpty() -> para fazer reset dos valores ao adicionar new stock
//
//
//
//
//
</script>
<style>
{
box-sizing: content-box;
}
/* Set additional styling options for the columns */
.column {
float: left;
}
/* Set width length for the left, right and middle columns */
.left {
width: 30%;
}
.right {
width: 80%;
}
.row:after {
content: "";
display: table;
clear: both;
height: 100%;
}
.td {
display: inline-block;
width: 120px;
text-align: center;
font-family: 'Trebuchet MS', sans-serif;
}
.tr {
font-family: 'Trebuchet MS', sans-serif;
}
.button1 {
width: 20%;
margin-left: 35%;
margin-right: 25%;
margin-top: 10px;
font-family: 'Trebuchet MS', sans-serif;
}
.button2 {
width: 20%;
margin-left: 35%;
margin-right: 25%;
margin-top: 10px;
font-family: 'Trebuchet MS', sans-serif;
}
.piechart {
width: 100%;
height: 100%;
}
</style>
</body>
</html>
I've also tried using Object.keys
to update all the quota
key values to the latest index value, but it isn't working as expected
2nd JS with the object.keys
implementation (line 125)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://www.gstatic.com/charts/loader.js"></script>
</head>
<body style="background-color:#DFCFBE">
<div class="row">
<div class="column left">
<form id=" form">
<div class="tr">
<div class="td">Asset </div>
<div class="td">Quota % </div>
<div class="td">Potencial Loss % </div>
</div>
<div class="tr" data-type="wrapper" data-index="1">
<div class="td" data-type="field_div"><input type="text" size="5" value="NEW STOCK" class="stock"
onchange="drawChart();" /> </div>
<div class="td"><input type="number" min="0" max="100" value="100" class="quota"
onchange="drawChart();" /> </div>
<div class="td"><input type="number" min="0" max="100" value="0" class="perda" />
</div>
</div>
<p onload="addNumAtivo();" id="indexSum">Number of Assets: 1</p>
<p onload="addNumAtivo();" id="indexQuota">Quota per asset: </p>
<p id="indexLoss">Total Loss:</p>
<button class="button2" type="button" onclick="addStock(event), addNumAtivo();">Add
Asset</button>
<button class="button1" type="button" onclick="drawChart();">Draw Graph</button>
</form>
</div>
</div>
<div class="column right" style="position:relative;width:70%">
<div class=" piechart" id="piechart" style="position:absolute;right:0px;top:0px;width: 900; height: 590px;">
</div>
</div>
</body>
<script>
//Define variables
let perda; //This value is calculated on line 154
let indexSum = 1, indexSumRatio = 1;
let valuePercentage = 100; //This value percentage is essentially the "Quota". This value will be 100% divided by the amount of indexSum (essentialy, divided by ativo1, ativo2, ativo3... ativo(i))
//valuePercentage.toFixed(2)
//let indexSumRatio = 1;
let numQuota = 100;
let numAtivo = 1;
document.getElementById("indexSum").innerHTML = `Number of Assets: ${numAtivo++}`;
document.getElementById("indexQuota").innerHTML = `Quota per asset: ${valuePercentage}%`;
//Functions that will increase the number of Assets and change the quota % as the user adds new assets (Add Stock) on the HTML
function addNumAtivo() {
document.getElementById("indexSum").innerHTML = `Number of Assets: ${numAtivo++}`;
document.getElementById("indexQuota").innerHTML = `Quota per asset: ${valuePercentage}%`;
}
document.getElementsByClassName("button2").onclick = numAtivo;
document.getElementsByClassName("button2").onclick = valuePercentage;
////////////////////////////////////////////////////////////////////////////////////
//Load google chart graphs
google.charts.load("current", {
packages: ["corechart"]
});
google.charts.setOnLoadCallback(drawChart);
// Function that will add new "Ativo", a new "Quota%" and a new "Perda potencial%" as the user presses the button "Add Stock".
function addStock(event) {
// find the last Wrapper [data-set="wrapper"]
let lastWrapper = event.currentTarget.form.querySelector(`[data-type="wrapper"]:last-of-type`);
// get the index of the last Wrapper
let lastIndex = parseInt(lastWrapper.dataset.index);
//clone the wrapper
let clonerNode = lastWrapper.cloneNode(true);
//change index of cloner Wrapper
indexSum = clonerNode.dataset.index = parseInt(lastIndex) + 1;
//changes values;
clonerNode.querySelector(`.stock`).value = "NEW STOCK";
valuePercentage = clonerNode.querySelector(`.quota`).value = (100 / indexSum);
//append clonernode after lastWrapper
lastWrapper.insertAdjacentElement('afterend', clonerNode);
indexSumRatio = 1 / indexSum;
console.log(`This is the sum of the indices (number of stocks = indexSum) ${indexSum}`)
console.log(`This is the valuePercentage (quota) ${valuePercentage}`)
console.log(`This is the indexSumRatio (perda potencial Ratio) ${indexSumRatio}`)
//colocar algo que faça reset aos valores
}
////////////////////////////////////////////////////////////////////////////////////
//Function that will be passed by the "Draw Graph" button so that everytime the user clicks the button, it takes the new input values and updates the pie chart
function drawChart() {
let ativo;
let quota;
let updateQuota;
let slices = []; //the amount of "slices" on the pie chart is also the number of indices added
for (let i = 1; i <= indexSum; i++) { //i <= slices.length
ativo = document.querySelector(`div [data-type="wrapper"][data-index="${i}"] .stock`).value;
quota = parseFloat(document.querySelector(`div [data-type="wrapper"][data-index="${i}"] .quota`).value);
slices.push({
ativo: ativo,
quota: quota
})
//updateQuota = slices[slices.length - 1]
}
Object.keys(slices).forEach(quota => { slices[quota] = slices[slices.length - 1] });
console.log(slices)
// //get last index - video 39 JS
//console.log(friends[friends.length-1])
//https://www.udemy.com/course/the-complete-javascript-course/learn/lecture/22648249#overview
// for (let j = 1; j <= indexSum - 1; j++) {
// slices.push({
// ativo: ativo,
// quota: quota
// })
// }
//Calculate the Loss (Perda) - this value is essentially the total amount of loss that the assets have taken when the user changes the "Perda potencial". This value is calculated by doing quota (valuePercentage) - perda potencial (perda) * (1/amount of assets)
document.querySelector(".row").addEventListener("input", function (e) {
const tgt = e.target;
if (tgt.classList.contains("perda")) {
perda = Number(tgt.closest(".tr").querySelector(".quota").value =
valuePercentage - tgt.value * indexSumRatio)
}
});
let sum = 0.0;
for (let i = 0; i < slices.length; i++) {
sum += slices[i].quota;
};
perda = Math.round(100.0 - sum);
console.log(`This is the Total Loss (perda) ${perda}`)
document.getElementById("indexLoss").innerHTML = `Total Loss: ${perda}%`;
document.getElementsByClassName("button2").onclick = perda;
//Create data table with input data
var data = new google.visualization.DataTable();
data.addColumn("string", "Ativo");
data.addColumn("number", "Quota");
data.addRows([
...slices.map(slice => ([slice.ativo, slice.quota])), ["Loss", perda],
]);
//Styling
let options = {
'legend': 'right',
pieHole: 0.3,
pieSliceText: 'value',
is3D: true,
colors: ['#FBB117', '#6AA121', '#728FCE', '#4863A0', '#7D0552', '#FF0000'],
backgroundColor: '#DFCFBE',
chartArea: {
left: 50,
right: 50,
top: 70
}
};
var chart = new google.visualization.PieChart(
document.getElementById("piechart")
);
chart.draw(data, options);
}
//adicionar for loop para ter o valor da quota personalizada e fazer os calculos da perda consoante esse valor
////////////////////////////////////////////////////////////////////////////////////
//RESOURCES
//https://www.youtube.com/watch?v=y17RuWkWdn8&ab_channel=WebDevSimplified
// usar este video para criar uma função que faça append de um novo div com atributos semelhantes aos outros para permitir ao usuario adicionar novos ativos com o cloque de um butao
//isEmpty() -> para fazer reset dos valores ao adicionar new stock
//
//
//
//
//
</script>
<style>
{
box-sizing: content-box;
}
/* Set additional styling options for the columns */
.column {
float: left;
}
/* Set width length for the left, right and middle columns */
.left {
width: 30%;
}
.right {
width: 80%;
}
.row:after {
content: "";
display: table;
clear: both;
height: 100%;
}
.td {
display: inline-block;
width: 120px;
text-align: center;
font-family: 'Trebuchet MS', sans-serif;
}
.tr {
font-family: 'Trebuchet MS', sans-serif;
}
.button1 {
width: 20%;
margin-left: 35%;
margin-right: 25%;
margin-top: 10px;
font-family: 'Trebuchet MS', sans-serif;
}
.button2 {
width: 20%;
margin-left: 35%;
margin-right: 25%;
margin-top: 10px;
font-family: 'Trebuchet MS', sans-serif;
}
.piechart {
width: 100%;
height: 100%;
}
</style>
</body>
</html>
Solution
Alright I'll take a shot at this one. You do have a lot of complex selectors that could probably be reduced and data should be contained in some sort of object or array instead of relaying on the UI elements for data.
With that aside I think you just need to loop through each stock's quota input and update it to whatever the valuePercentage
is you calculate.
This can be done with
document.querySelectorAll('.quota').forEach(function(quota) {
quota.value = valuePercentage;
});
I also removed the ["Loss", perda]
piece from the data.addRows
since it eventually goes negative and you can't pie chart negative data.
//Define variables
let perda; //This value is calculated on line 154
let indexSum = 1;
let valuePercentage = 100; //This value percentage is essentially the "Quota". This value will be 100% divided by the amount of indexSum (essentialy, divided by ativo1, ativo2, ativo3... ativo(i))
let indexSumRatio = 1;
let numQuota = 100;
let numAtivo = 1;
document.getElementById("indexSum").innerHTML = `Number of Assets: ${numAtivo++}`;
document.getElementById("indexQuota").innerHTML = `Quota per asset: ${valuePercentage}%`;
//Functions that will increase the number of Assets and change the quota % as the user adds new assets (Add Stock) on the HTML
function addNumAtivo() {
document.getElementById("indexSum").innerHTML = `Number of Assets: ${numAtivo++}`;
document.getElementById("indexQuota").innerHTML = `Quota per asset: ${valuePercentage}%`;
}
document.getElementsByClassName("button2").onclick = numAtivo;
document.getElementsByClassName("button2").onclick = valuePercentage;
////////////////////////////////////////////////////////////////////////////////////
//Load google chart graphs
google.charts.load("current", {
packages: ["corechart"]
});
google.charts.setOnLoadCallback(drawChart);
// Function that will add new "Ativo", a new "Quota%" and a new "Perda potencial%" as the user presses the button "Add Stock".
function addStock(event) {
// find the last Wrapper [data-set="wrapper"]
let lastWrapper = event.currentTarget.form.querySelector(`[data-type="wrapper"]:last-of-type`);
// get the index of the last Wrapper
let lastIndex = parseInt(lastWrapper.dataset.index);
//clone the wrapper
let clonerNode = lastWrapper.cloneNode(true);
//change index of cloner Wrapper
indexSum = clonerNode.dataset.index = parseInt(lastIndex) + 1;
//changes values;
clonerNode.querySelector(`.stock`).value = "NEW STOCK";
valuePercentage = clonerNode.querySelector(`.quota`).value = (100 / indexSum);
//append clonernode after lastWrapper
lastWrapper.insertAdjacentElement('afterend', clonerNode);
indexSumRatio = 1 / indexSum;
document.querySelectorAll('.quota').forEach(function(quota) {
quota.value = valuePercentage;
});
//console.log(`This is the sum of the indices (number of stocks = indexSum) ${indexSum}`)
//console.log(`This is the valuePercentage (quota) ${valuePercentage}`)
// console.log(`This is the indexSumRatio (perda potencial Ratio) ${indexSumRatio}`)
}
////////////////////////////////////////////////////////////////////////////////////
//Function that will be passed by the "Draw Graph" button so that everytime the user clicks the button, it takes the new input values and updates the pie chart
function drawChart() {
let slices = []; //the amount of "slices" on the pie chart is also the number of indices added
for (let i = 1; i <= indexSum; i++) { //i <= slices.length
slices.push({
ativo: document.querySelector(`div [data-type="wrapper"][data-index="${i}"] .stock`).value,
quota: parseFloat(document.querySelector(`div [data-type="wrapper"][data-index="${i}"] .quota`).value)
})
}
//Calculate the Loss (Perda) - this value is essentially the total amount of loss that the assets have taken when the user changes the "Perda potencial". This value is calculated by doing quota (valuePercentage) - perda potencial (perda) * (1/amount of assets)
document.querySelector(".row").addEventListener("input", function(e) {
const tgt = e.target;
if (tgt.classList.contains("perda")) {
perda = Number(tgt.closest(".tr").querySelector(".quota").value =
valuePercentage - tgt.value * indexSumRatio)
}
});
let sum = 0.0;
for (let i = 0; i < slices.length; i++) {
sum += slices[i].quota;
};
perda = 100.0 - sum;
console.log(`This is the Total Loss (perda) ${perda}`)
document.getElementById("indexLoss").innerHTML = `Total Loss: ${perda}%`;
document.getElementsByClassName("button2").onclick = perda;
//Create data table with input data
var data = new google.visualization.DataTable();
data.addColumn("string", "Ativo");
data.addColumn("number", "Quota");
data.addRows([
...slices.map(slice => ([slice.ativo, slice.quota])),
]);
//Styling
let options = {
'legend': 'right',
pieHole: 0.3,
pieSliceText: 'value',
is3D: true,
colors: ['#FBB117', '#6AA121', '#728FCE', '#4863A0', '#7D0552', '#FF0000'],
backgroundColor: '#DFCFBE',
chartArea: {
left: 50,
right: 50,
top: 70
}
};
var chart = new google.visualization.PieChart(
document.getElementById("piechart")
);
chart.draw(data, options);
}
{
box-sizing: content-box;
}
/* Set additional styling options for the columns */
.column {
float: left;
}
/* Set width length for the left, right and middle columns */
.left {
width: 30%;
}
.right {
width: 80%;
}
.row:after {
content: "";
display: table;
clear: both;
height: 100%;
}
.td {
display: inline-block;
width: 120px;
text-align: center;
font-family: 'Trebuchet MS', sans-serif;
}
.tr {
font-family: 'Trebuchet MS', sans-serif;
}
.button1 {
width: 20%;
margin-left: 35%;
margin-right: 25%;
margin-top: 10px;
font-family: 'Trebuchet MS', sans-serif;
}
.button2 {
width: 20%;
margin-left: 35%;
margin-right: 25%;
margin-top: 10px;
font-family: 'Trebuchet MS', sans-serif;
}
.piechart {
width: 100%;
height: 100%;
}
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://www.gstatic.com/charts/loader.js"></script>
</head>
<body style="background-color:#DFCFBE">
<div class="row">
<div class="column left">
<form id=" form">
<div class="tr">
<div class="td">Asset </div>
<div class="td">Quota % </div>
<div class="td">Potencial Loss % </div>
</div>
<div class="tr" data-type="wrapper" data-index="1">
<div class="td" data-type="field_div">
<input type="text" size="5" value="NEW STOCK" class="stock" onchange="drawChart();" />
</div>
<div class="td">
<input type="number" min="0" max="100" value="100" class="quota" onchange="drawChart();" />
</div>
<div class="td">
<input type="number" min="0" max="100" value="0" class="perda" />
</div>
</div>
<p onload="addNumAtivo();" id="indexSum">Number of Assets: 1</p>
<p onload="addNumAtivo();" id="indexQuota">Quota per asset: </p>
<p id="indexLoss">Total Loss:</p>
<button class="button2" type="button" onclick="addStock(event), addNumAtivo();">Add
Asset</button>
<button class="button1" type="button" onclick="drawChart();">Draw Graph</button>
</form>
</div>
</div>
<div class="column right" style="position:relative;width:70%">
<div class=" piechart" id="piechart" style="position:absolute;right:0px;top:0px;width: 900; height: 590px;">
</div>
</div>
</body>
Answered By - Andrew Lohr
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.