I have created a class that takes computer parts and their costs and calculates them based on what parts are chosen. At the moment I have two functions, one to add more parts to the quote and one to remove parts. It works correctly in the sense of removing or adding items, but does not change the total cost. When I remove parts, the price remains the same, likewise if I add more parts. What could I do to get this working as expected. Here is the code:
class PriceCalc {
Motherboard = 520.99;
RAM = 250.4;
SSD = 500.8;
HDD = 400.66;
Case = 375.5;
Monitor = 600.75;
Keyboard = 100.99;
Mouse = 25.5;
constructor(Obj) {
this.parts = Obj;
this.cost = "$" + Obj.reduce((a, b) => a + this[b], 0).toFixed(2);
this.retail ="$" +(Obj.reduce((a, b) => a + this[b], 0) +Obj.reduce((a, b) => a + this[b], 0) * 1.75).toFixed(2);
this.quote = "Your quote is " + this.retail;
}
add(item) {
this.parts = [...this.parts, item];
}
remove(item) {
this.parts = this.parts.filter((x) => x !== item);
}
}
quote4 = new PriceCalc(["RAM", "SSD", "Case", "Mouse"]);
console.log(quote4.parts);//Returns ["RAM", "SSD", "Case", "Mouse"]
console.log(quote4.cost);//Returns $1152.20
console.log(quote4.retail);//Returns $3168.55
console.log(quote4.quote);//Returns "Your quote is $3168.55"
quote4.remove("Case")
console.log(quote4.parts);//Returns ["RAM", "SSD", "Mouse"]
console.log(quote4.cost);//Returns $1152.20
console.log(quote4.retail);//Returns $3168.55
console.log(quote4.quote);//Returns "Your quote is $3168.55"
At the moment this.cost/retail/quote doesnt change when things are added or removed, whereas they should be modified if items are added or removed. The only way I can change the values at the moment is by manually changing the parts within the called array. How could I fix this?
You need to recalculate them whenever a new item gets added or an item is removed. Since they need to be recalculated from different places (the constructor, add and remove), a new method (called calculate or update for example) is perfect for this as reusable code should be grouped in a function/method so you don't repeat yourself.
Also, cost and retail should be numbers instead of strings. You are using reduce to calculate cost, then using the same reduce twice to calculate retail which should be avoided. Just calculate cost and use cost to calculate retail.
Finally, add and remove should not create new arrays each time an item is removed or added.
class PriceCalc {
Motherboard = 520.99;
RAM = 250.4;
SSD = 500.8;
HDD = 400.66;
Case = 375.5;
Monitor = 600.75;
Keyboard = 100.99;
Mouse = 25.5;
constructor(initialParts) { // always choose good names for your variables. initialParts makes more sense than Obj
this.parts = initialParts; // store the initial parts
calculate(); // calculate cost, retail and quote
}
add(item) {
this.parts.push(item); // use push instead of creating a new array (which is an overkill)
calculate(); // recalculate cost, retail and quote
}
remove(item) {
this.parts = this.parts.filter((x) => x !== item); // I'd rather use this https://stackoverflow.com/a/5767357 over filter but filter is shorter so OK
calculate(); // recalculate cost, retail and quote
}
calculate() { // the method that calculates cost, retail and quote
this.cost = this.parts.reduce((a, b) => a + this[b], 0); // calculate cost and store as a number instead of a string
this.retail = this.cost + this.cost * 1.75; // calculate retail using the value of this.cost and also store as a number (you can use this.retail = 2.75 * this.cost; which is the same)
this.quote = "Your quote is $" + this.retail.toFixed(2); // generate the quote (notice the added $ sign and the call to toFixed(2))
}
}
Related
I have two values on my html page, that I got from a form.
The person completes the amount of money they have on one input, and on the other input, the number of people.
So, my question is:
How do i divide the amount.value by the people.value, and distribute it, in a way it appears as shown in the example below?
Amount: 150 / Number of People: 3
-Person 1 - 50
-Person 2 - 50
-Person 3 - 50
What i'm actually struggling with, is to create a function that will add to the HMTL another person + the result, depending on the number of people added previously.
The code down below just finds the total share of all people and distributes the amount among them dependin on their shares.
/*----- Define your variables in here ------*/
var amount = 150;
var people = {
1: 0.75,
2: 0.15,
3: 0.10
}
var totalSharePerc = 0;
/*----- Loop thruogh people to calculate total sum ------*/
for (const [key, value] of Object.entries(people)) {
totalSharePerc = totalSharePerc + value;
}
/*----- Loop thruogh people and split the amount ------*/
for (const [key, value] of Object.entries(people)) {
/*------ Calculate share of person -----*/
var share = (amount*value/totalSharePerc);
/*----- Do whatever you want ------*/
console.log("Person"+key+" => "+share);
}
You can use Array#reduce() to calculate the total share for every person involved.
This assumes you have a mapping defined of which person has to cover which share (which you will need to have if you want to distribute in non-equal shares).
const amount = 150;
// define mapping of percentages to persons
const sharesPerPersonPct = {
1: 0.75,
2: 0.15,
3: 0.1,
};
// create a mapping of total values to persons
const sharesPerPersonTotal = Object.entries(sharesPerPersonPct).reduce(
(allShares, [personId, share]) => {
allShares[personId] = {
pct: share, // add percentage (optional)
total: amount * share // add total share
}
return allShares;
},
{}
);
console.log("Resulting JS object:")
console.log(sharesPerPersonTotal);
Object.entries(sharesPerPersonTotal).forEach(([personId, share]) => console.log(`Person ${personId} has to cover ${(share.pct * 100).toFixed(2)}% which amounts to ${share.total}$.`))
Updated answer to reflect your edit
The following is for an equal distribution of an amount to a number of people. The challenge is that e.g 10$ cannot be distributed 3.33$ for each of 3 persons as then penny would be missing. This is the sort of stuff you get when using floating point arithmetic. To prevent that use integer arithmetic instead. So multiply 10$ by 100 so you get 1000p and you can then assign each person their floored share (Math.floor(1000 / 3) = 333) use modulo to get the remainder (10 % 3 = 1) and distribute that remainder among the persons involved. The current implementation isn't quite fair either though because it always assigns that one penny more starting from the front, but you could use something like this to account for that.
The rest is just input validation using RegEx and displaying the results doing some DOM manipulation.
function handleUpdateDistribution() {
const amountMoney = document.getElementById("amount-money");
const noPersons = document.getElementById("no-persons");
if (!isMoneyValid(amountMoney.value)) {
console.log("Money value can only have two decimal places!");
return;
}
if (!isNoPersonValid(amountMoney.value)) {
console.log("Number of persons must be an integer greater than one!");
return;
}
const distribution = updateDistribution(
Number.parseInt(noPersons.value),
Number.parseFloat(amountMoney.value)
);
showDistribution(distribution);
}
function isMoneyValid(money) {
const matches = money.match(/^[0-9]+(\.[0-9]{1,2})?$/g);
if (matches === null) return null;
else return matches[0];
}
function isNoPersonValid(noPersons) {
const matches = noPersons.match(/[1-9]*/g);
if (matches === null) return null;
else return matches[0];
}
function showDistribution(distribution) {
const list = document.createElement("ul");
const listItems = Object.entries(distribution).map(([personId, share]) => {
const item = document.createElement("li");
item.textContent = `Person ${personId} has to cover ${share}$.`;
return item;
});
list.append(...listItems);
document.getElementById("result").replaceChildren(list);
}
/**
*
* #param {number} noPersons number of persons to split between
* #param {number} amountMoney amount of money to split
*/
function updateDistribution(noPersons, amountMoney) {
// use integer arithmetic as floating point arithmetic is not very suitable for task at hand
amountMoney *= 100;
const share = Math.floor(amountMoney / noPersons);
let remainder = amountMoney % noPersons;
const persons = {};
for (let i = 1; i <= noPersons; i++) {
const shareInInts = share + (remainder > 0 ? 1 : 0);
remainder--;
persons[i] = (shareInInts / 100).toFixed(2);
}
return persons;
}
window.addEventListener("DOMContentLoaded", (e) => {
const amountMoney = document.getElementById("amount-money");
const noPersons = document.getElementById("no-persons");
amountMoney.addEventListener("input", handleUpdateDistribution);
noPersons.addEventListener("input", handleUpdateDistribution);
});
input:invalid {
border: red solid 3px;
}
<form>
<input id="no-persons" placeholder="Number of persons" type="number" required />
<input id="amount-money" placeholder="Amount of money" type="text" pattern="^[0-9]+(\.[0-9]{1,2})?$" required />
</form>
<div id="result"></div>
Please note you can and should do more to give the user a nice user experience (Show popovers instead of console.log(), nicer styling etc). See MDN docs on form validation. You should also probably restrict the number of persons as rendering thousands of list items will seriously impact the performance.
I need to make a bin counter. It will be specific to my data, but as an example, I will use a grocery store. I see a lot of ways to increment items, but this would be more like counting the number of distinct entries in an SQL column (which I am not good at, either).
Say the grocery store wanted to count the number of items they sold every day through the cash register. Apples and milk are likely to have high counts at the end of the day, but the array has to be able to add elements from the inventory, even if they don't sell often.
function onDataBound(e) {
var grid = $('grid').data('kendoGrid');
const binCounter = {};
$.each(grid.items(), function (index, item) {
var row = dataSource.getByUid($(item).data('uid'));
var itemName = row.ItemName; // apples, milk, condoms, hammers, etc.
var soldAs = row.SoldAs; // each, 6-pack, carton, dozen, case, etc.
var itemColor = row.ItemColor;
// help needed here
binCounter[itemName]++;
binCounter[soldAs]++;
binCounter[itemColor]++;
});
$.each(binCounter, function (index, item) {
console.log('binCounter[' + index + ']:');
console.log(item);
})
};
The results would have the number of binCounter['apple'] and binCounter['milk'] stored.
You can't increment a bin that hasn't been initialized yet. You have to check whether the bin exists first.
So instead of
binCounter[itemName]++;
you need
if (binCounter[itemName]) {
binCounter[itemName]++;
} else {
binCounter[itemName] = 1;
}
Since you need to do this repeatedly, you could write a function for it:
function increment_bin(binCounter, key) {
if (binCounter[itemName]) {
binCounter[itemName]++;
} else {
binCounter[itemName] = 1;
}
}
Then you can do
increment_bin(binCounter, itemName);
increment_bin(binCounter, soldAs);
increment_bin(binCounter, itemColor);
I need to take the price and tax of these and return the total of everything. I'm learning so I apologize for the simple question.
const orders = [{"price":15,"tax":0.09},{"price":42,"tax":0.07},{"price":56,"tax":0.11},
{"price":80,"tax":0.11},{"price":69,"tax":0.06},{"price":68,"tax":0.14},
{"price":72,"tax":0.14},{"price":51,"tax":0.09},{"price":89,"tax":0.15},
{"price":48,"tax":0.13}];
// Do not edit code above.
/*
Use a higher-order method to get the sum of all the order totals after adding in the sales tax
*/
var ordersTotal = orders.reduce(function(total, num) {
return total + num;
})
ordersTotal;
Simply use Array.reduce() and Object destructing. And please make sure to pass 0 as the initial value to your reduce function.
const orders = [{"price":15,"tax":0.09},{"price":42,"tax":0.07},{"price":56,"tax":0.11},{"price":80,"tax":0.11},{"price":69,"tax":0.06},{"price":68,"tax":0.14},{"price":72,"tax":0.14},{"price":51,"tax":0.09},{"price":89,"tax":0.15},{"price":48,"tax":0.13}];
const result = orders.reduce((a,{price,tax})=>a+price+tax,0);
console.log(result);
You need to give reduce something to start with, in this example 0 is probably a good start. Then each num passed to reduce will be an object. Currently you're just adding the object like total = total + {"price":15,"tax":0.09} and that doesn't work. You need to look at each property you want to add. It's not clear if tax is a percentage or a total amount. Below we'll just add it, but it should be clear how to add as a percentage if you want.
const orders = [{"price":15,"tax":0.09},{"price":42,"tax":0.07},{"price":56,"tax":0.11},{"price":80,"tax":0.11},{"price":69,"tax":0.06},{"price":68,"tax":0.14},{"price":72,"tax":0.14},{"price":51,"tax":0.09},{"price":89,"tax":0.15},{"price":48,"tax":0.13}];
var ordersTotal = orders.reduce(function(total, num) {
return total + num.price + num.tax; // add properties
}, 0) // start with 0
console.log(ordersTotal);
Make sure you start with a zero so it doesn't try to coerce the result into a string.
const orders = [{"price":15,"tax":0.09},{"price":42,"tax":0.07},{"price":56,"tax":0.11},
{"price":80,"tax":0.11},{"price":69,"tax":0.06},{"price":68,"tax":0.14},
{"price":72,"tax":0.14},{"price":51,"tax":0.09},{"price":89,"tax":0.15},
{"price":48,"tax":0.13}];
// Do not edit code above.
var ordersTotal = orders.reduce(function(total, order) {
return total + order.price + order.tax;
},0)
console.log(ordersTotal,ordersTotal.toFixed(2))
Consider the following scenario:
One million clients visit a store and pay an amount of money using their credit card. The credit card codes are generated using a 16-digit number, and replacing 4 of its digits (randomly) with the characters 'A', 'B', 'C', 'D'. The 16-digit number is generated randomly once, and is used for every credit card, the only change between cards being the positions in the string of the aforementioned characters (that's ~40k possible distinct codes).
I have to organize the clients in a hash table, using a hash function of my choosing and also using open addressing (linear probing) to deal with the collisions. Once organized in the table, I have to find the client who
paid the most money during his purchases.
visited the store the most times.
My implementation of the hash table is as follows, and seems to be working correctly for the test of 1000 clients. However once I increase the number of clients to 10000 the page never finishes loading. This is a big issue since the total number of "shopping sessions" has to be one million, and I am not even getting close to that number.
class HashTable{
constructor(size){
this.size = size;
this.items = new Array(this.size);
this.collisions = 0;
}
put(k, v){
let hash = polynomial_evaluation(k);
//evaluating the index to the array
//using modulus a prime number (size of the array)
//This works well as long as the numbers are uniformly
//distributed and sparse.
let index = hash%this.size;
//if the array position is empty
//then fill it with the value v.
if(!this.items[index]){
this.items[index] = v;
}
//if not, search for the next available position
//and fill that with value v.
//if the card already is in the array,
//update the amount paid.
//also increment the collisions variable.
else{
this.collisions++;
let i=1, found = false;
//while the array at index is full
//check whether the card is the same,
//and if not then calculate the new index.
while(this.items[index]){
if(this.items[index] == v){
this.items[index].increaseAmount(v.getAmount());
found = true;
break;
}
index = (hash+i)%this.size;
i++;
}
if(!found){
this.items[index] = v;
}
found = false;
}
return index;
}
get(k){
let hash = polynomial_evaluation(k);
let index = hash%this.size, i=1;
while(this.items[index] != null){
if(this.items[index].getKey() == k){
return this.items[index];
}
else{
index = (hash+i)%this.size;
i++;
}
}
return null;
}
findBiggestSpender(){
let max = {getAmount: function () {
return 0;
}};
for(let item of this.items){
//checking whether the specific item is a client
//since many of the items will be null
if(item instanceof Client){
if(item.getAmount() > max.getAmount()){
max = item;
}
}
}
return max;
}
findMostFrequentBuyer(){
let max = {getTimes: function () {
return 0;
}};
for(let item of this.items){
//checking whether the specific item is a client
//since many of the items will be null
if(item instanceof Client){
if(item.getTimes() > max.getTimes()){
max = item;
}
}
}
return max;
}
}
To key I use to calculate the index to the array is a list of 4 integers ranging from 0 to 15, denoting the positions of 'A', 'B', 'C', 'D' in the string
Here's the hash function I am using:
function polynomial_evaluation(key, a=33){
//evaluates the expression:
// x1*a^(d-1) + x2*a^(d-2) + ... + xd
//for a given key in the form of a tuple (x1,x2,...,xd)
//and for a nonzero constant "a".
//for the evaluation of the expression horner's rule is used:
// x_d + a*(x_(d-1) + a(x_(d-2) + .... + a*(x_3 + a*(x_2 + a*x1))... ))
//defining a new key with the elements of the
//old times 2,3,4 or 5 depending on the position
//this helps for "spreading" the values of the keys
let nKey = [key[0]*2, key[1]*3, key[2]*4, key[3]*5];
let sum=0;
for(let i=0; i<nKey.length; i++){
sum*=a;
sum+=nKey[i];
}
return sum;
}
The values corresponding to the keys generated by the hash function are instances of a Client class which contains the fields amount (the amount of money paid), times (the times this particular client shopped), key (the array of 4 integers mentioned above), as well as getter functions for those fields. In addition there's a method that increases the amount when the same client appears more than once.
The size of the hash table is 87383 (a prime number) and the code in my main file looks like this:
//initializing the clients array
let clients = createClients(10000);
//creating a new hash table
let ht = new HashTable(N);
for(let client of clients){
ht.put(client.getKey(), client);
}
This keeps running until google chrome gives a "page not responding" error. Is there any way I can make this faster? Is my approach on the subject (perhaps even my choice of language) correct?
Thanks in advance.
The page is not responding since the main (UI) thread is locked. Use a WebWorker or ServiceWorker to handle the calculations, and post them as messages to the main thread.
Regarding optimizing your code, one thing I see is in findBiggestSpender. I'll break it down line-by-line.
let max = {getAmount: function () {
return 0;
}};
This is a waste. Just assign a local variable, no need to keep calling max.getAmount() in every iteration.
for(let item of this.items){
The fastest way to iterate a list in Javascript is with a cached length for loop: for (let item, len = this.items.length; i < len; i ++)
if(item instanceof Client){
This is slower than a hard null check, just use item !== null.
I have this object resources:
var resources = { //Handles resources of all kinds.
number: 100,
money: 23000000,
science: 1000,
popularity: {
amount: 0,
upgProd: 0 //Amount produced from upgrades.
}
};
This looks like a normal object.
However, I'm trying to display a certain quantity popularity. Every time I try to display it, I get a NaN instead of a number.
I try to return console.log(resources.popularity.upgProd); but I still end up getting an undefined. I have no clue why since I define the variable but I still get undefined...
No errors in the IDE or in the console, just undefined when I console.log().
EDIT: Here is some surrounding context... this is my update function, that updates every 1/7 second. ALSO, the first value of resources.popularity.upgProd is 0, then the next become NaN.
function update() {
buffer++;
if (buffer == 35) {
checkVisibilityOnBuildings();
checkVisiblityOnUpgrades();
checkVisibilityOnResources();
buffer = 0;
} // Every 5 seconds (35 ticks) visibility will be checked and updated.
/* Number increasing. A bit tedious but no other way to do it yet. */
resources.number +=
((BUILDINGS[0].numProdBase * BUILDINGS[0].count) + //Now it's easy! Just do UPGRADES[n+1] for the next building.
(BUILDINGS[1].numProdBase * BUILDINGS[1].count) +
(BUILDINGS[2].numProdBase * BUILDINGS[2].count) +
(BUILDINGS[3].numProdBase * BUILDINGS[3].count));
//Science gained per tick. Var used to make the "scienceProductionTotalDisp" work properly
var scienceTotalPerTick =
(BUILDINGS[2].sciProdBase * BUILDINGS[2].count) +
(BUILDINGS[3].sciProdBase * BUILDINGS[3].count);
resources.science += scienceTotalPerTick;
//Display vars for html so that rounding errors don't happen.
var numDisp = Math.floor(resources.number);
var sciDisp = Math.floor(resources.science * 100) / 100;
var popDisp = Math.floor(resources.popularity.amount * 100) / 100;
console.log(Number(resources.popularity.upgProd));
var moneyTotalPerTick = Math.pow(resources.number, (1/(player.moneyRatio))) + 1; //Cash flow per 143ms (7n for total / sec ish)
var popularityTotalPerTick = (Number(resources.popularity.upgProd)) + 0;
resources.popularity += popularityTotalPerTick;
console.log(resources.popularity.upgProd);
resources.money += moneyTotalPerTick;
getId('moneyProductionTotalDisp').innerHTML = numFormat(Math.floor(moneyTotalPerTick * 7));
getId('moneyDisp').innerHTML = numFormat(Math.round(resources.money * 100) / 100);
getId('numberDisp').innerHTML = numFormat(numDisp);
getId('scienceDisp').innerHTML = numFormat(sciDisp);
getId('popularityDisp').innerHTML = numFormat(popDisp);
getId('scienceProductionTotalDisp').innerHTML =
numFormat(Math.floor(scienceTotalPerTick * 700) / 100);
getId('popularityProductionTotalDisp').innerHTML =
numFormat(Math.floor(popularityTotalPerTick * 700) / 100);
Thank you!
Here is your problem:
resources.popularity += popularityTotalPerTick;
popularity is an object, and that doesn't do what you want.
Since you overwrite it with the result of an object added by a value, you assign it s string [object Object]9 where the last digit is whatever was in popularityTotalPerTick.
You get NaN (Not a number) since you are using Number(x)in console.log(Number(resources.popularity.upgProd));. Why are you doing that?
Does getId do a lookup of the element in the dom every time your function is called? Have the object changed or are you querying the DOM for the same element 7 times per second?
Some thoughts about the other tings in your code:
resources.number +=
((BUILDINGS[0].numProdBase * BUILDINGS[0].count) +
(BUILDINGS[1].numProdBase * BUILDINGS[1].count) +
(BUILDINGS[2].numProdBase * BUILDINGS[2].count) +
(BUILDINGS[3].numProdBase * BUILDINGS[3].count));
I'm assuming that BUILDINGS is an array with all the buildings, and that you want to calculate the number of all buildings in the array. There is a function for that: reduce that takes two parameters: a function and the start value:
resources.number += // do you really want += here and not just = ?
BUILDINGS.reduce( (sum, item) => sum + (item.numProdBase * item.count), 0 );
If your aren't familiar with arrow-functions it could be replaced with:
function (sum, item) { return sum + (item.numProdBase * item.count) }
var scienceTotalPerTick =
(BUILDINGS[2].sciProdBase * BUILDINGS[2].count) +
(BUILDINGS[3].sciProdBase * BUILDINGS[3].count);
I'm not sure why you are only doing it for two buildings, and not for all, but you could use reduce here too, with slice
var scienceTotalPerTick =
BUILDINGS.slice(2,4).reduce( (sum, item) => sum + (item.sciProdBase * item.count), 0);
Notice that the parameters to slice is begin to end (end not included), therefor 2,4 gives you element 2 and 3.
With this part of the code...
getId('moneyProductionTotalDisp').innerHTML = numFormat(Math.floor(moneyTotalPerTick * 7));
getId('moneyDisp').innerHTML = numFormat(Math.round(resources.money * 100) / 100);
getId('numberDisp').innerHTML = numFormat(numDisp);
getId('scienceDisp').innerHTML = numFormat(sciDisp);
getId('popularityDisp').innerHTML = numFormat(popDisp);
I assume that getId is a function that fetches the element via document.getElementById or document.querySelector, and that you do this for every frame, and you get the same element every time. Now imagine that the element is a box, and that I demand that you get it from the warehouse that is on the other side of the world. When you deliver the box, I open the box, replace the contents and send it back to the warehouse on the other side of the world. When you come back, I demand that you get the same box again, and you now have to travel to the other side of the world once again... and when you come back the story repeats...
My point here is that it is very wasteful to travel to the other side of the world each time to get the same box, or to get the same element from the DOM at each update. You could cache the elements by looking them up ONE time before you start the update, and you can put the result in an object:
function getElementsToUpdate() {
return {
moneyProductionTotalDisp: getId('moneyProductionTotalDisp'),
moneyDisp: getId('moneyDisp'),
// and so on...
}
}
If you name the property in the object the same as the id, you can put all the names in an array, and then reduce it to an object. This saves you some typing, and hard to find bugs because of a misspelled name:
function getElementsToUpdate() {
return [
'moneyProductionTotalDisp',
'moneyDisp',
'numberDisp',
'scienceDisp',
'popularityDisp',
// and so on....
].reduce(
(out, id) => { out[id] = getId(id); return out; }, {}
)
}
NOTE: This function should be run ONE time at startup, not for every update of the frame. It returns an object with the elements.
Somewhere in your code I assume that you use setInterval to call your update function. Since setInteval can take extra parameters that will be given to the called function, you can do something like this:
var timerHandle = setInterval( update, 1000/7, getElementsToUpdate() );
where update is your function, 1000/7 gives you the interval for 7 times a second, and getElementsToUpdate is the function that makes the time-expensive call to get the elements from the DOM one time.
You need to change the update function to take a parameter (the name is not important, but should be short and descriptive, so I use elem). This is the object that getElementsToUpdate() have returned with all the html-elements.
function update(elem) {
// ... your code ....
// Old code, that makes an expensive lookup into the DOM, and start a HTML parser.
// getId('numberDisp').innerHTML = numFormat(numDisp);
// New code, that gets the pre-looked up element and set the text.
elem.numberDisp.textContent = numFormat(numDisp);
}
I'm not a fan of using .innerHTML when it isn't html that is inserted. Always use .textContent instead, if is isn't html. In this case it would be better if you use the output-element, and set the .value property.
try using console.log(resources["popularity"]["upgProd"])