setAttribute not working consistently on change event - javascript

I'm having trouble getting a set of change events to work consistently: I have a table set up that checks to see whether either an input has been updated and then, depending on what input gets updated, the code submitted below either changes the margin or the price.
If I only change the price, I consistently calculate margin correctly, and if I only change the margin, I consistently calculate price correctly. If I change one and then the other, the second setAttribute doesn't work. (e.g. changing the price updates the margin, but, after that, changing margin, does not update price).
I'm new to JS, but I've tried debugging and can't seem to nail this down. Any help would be much appreciated.
see link for codepen: https://codepen.io/skeanerw/pen/mdBpppE
function calcBuySellMargin(bracket, rowID) {
const vendPriceID = document.getElementById(`VendPrice_${bracket}_${rowID}`);
const sellPriceID = document.getElementById(`ItemPrice_${bracket}_${rowID}`);
const marginID = document.getElementById(`Margin_${bracket}_${rowID}`);
const priceMeth = document.getElementById(`priceMeth_${rowID}`).innerText;
const vpUOM = document.getElementById(`vpUOM_${rowID}`).innerText;
//when we change the margin adjust the sell price.
marginID.addEventListener('change', () => {
let marginValue = (marginID.value) / 100
let vendPriceValue = (vpUOM === 'M') ? vendPriceID.value / 1000 : vendPriceID.value;
let sellPriceVal = (priceMeth === 'M') ? ((vendPriceValue / (1 - marginValue)) * 1000).toFixed(0) : (vendPriceValue / (1 - marginValue)).toFixed(3);
sellPriceID.setAttribute('value', parseFloat(sellPriceVal));
})
//when we change the buy price or the sell price, adjust the margin.
function setMargin() {
let vendPriceValue = (vpUOM === 'M') ? vendPriceID.value / 1000 : vendPriceID.value;
let sellPriceVal = (priceMeth === 'M') ? sellPriceID.value / 1000 : sellPriceID.value;
const marginValue = parseFloat( (sellPriceVal - vendPriceValue) / sellPriceVal * 100 )
marginID.setAttribute('value', parseFloat(marginValue).toFixed(0));
}
vendPriceID.addEventListener('change', () => {
setMargin()
})
sellPriceID.addEventListener('change', () => {
setMargin()
})
}
window.onload = (event) => {
document.querySelectorAll('.marginDisplay').forEach(element => {
const rowID = (element.id.replace(/Margin_\d_/, ''));
let bracket = (element.id.replace(/Margin_/,''))
bracket = (bracket.match(/^[0-9]/, ''))
calcBuySellMargin(bracket, rowID);
})
}

I was able to resolve by replacing the setAttribute methods:
marginID.addEventListener('change', () => {
let marginValue = (marginID.value) / 100
let vendPriceValue = (vpUOM === 'M') ? vendPriceID.value / 1000 : vendPriceID.value;
let sellPriceVal = (priceMeth === 'M') ? ((vendPriceValue / (1 - marginValue)) * 1000).toFixed(0) : (vendPriceValue / (1 - marginValue)).toFixed(3);
sellPriceID.value = sellPriceVal;
})
function setMargin() {
let vendPriceValue = (vpUOM === 'M') ? vendPriceID.value / 1000 : vendPriceID.value;
let sellPriceVal = (priceMeth === 'M') ? sellPriceID.value / 1000 : sellPriceID.value;
const marginValue = parseFloat( (sellPriceVal - vendPriceValue) / sellPriceVal * 100 )
marginID.value = marginValue
}

Related

How to multiply the values of two objects i.e. slider and number input in Javascript

I want multiply the values of two objects in javascript and want to show in innerHtml of rangeV, But I am getting issues. Please help. The code is given below. Also, I have attached a picture of code and highlighted the issue.
const range = document.getElementById("range"),
rangeV = document.getElementById("rangeV"),
inp5 = document.getElementById("myinput"),
inp6 = inp5.value,
inp7 = 2;
setValue = () => {
const newValue = Number(
((range.value - range.min) * 100) / (range.max - range.min)
),
newPosition = 10 - newValue * 0.2;
var val1 = range.value * inp7;
rangeV.innerHTML = `<span>${val1}</span>`;
rangeV.style.left = `calc(${newValue}% + (${newPosition}px))`;
// $(".forspace").html(range.value);
};
document.addEventListener("DOMContentLoaded", setValue);
range.addEventListener("input", setValue);

Creating dynamic split functionality using sliders

Currently I'm creating an application where the user can split the bill to individual candidates. Initially the slider values are equal for all candidates and the user can adjust them on the page accordingly where to increase someone's percentage, they have to decrease someone else's first. If the total amount of all sliders equal to 100, the sliders cannot move further which I'm achieving using upperLimit in the slider library
So far I've been able to achieve this with 2 users where I basically hardcoded the states and the logic by saying if when slider 1 is moved and state1 + state2 < 101 then pass the value 100 - (slider 1 value) to the slider 2 value. I'm achieving this with the following code:
const SplitBillPage = () => {
const splitUsers = 2;
const equalValueSplit = 100 / splitUsers;
const [range, setRange] = useState(equalValueSplit + '%');
const [secondRange, setSecondRange] = useState(equalValueSplit + '%');
const [limit, setLimit] = useState(100);
const [limitSecond, setLimitSecond] = useState(100);
function rangeSetter(value) {
setRange(parseInt(value) + '%');
let x = range;
let y = secondRange;
let withoutPercentage = x.replace('%', '');
let withoutPercentageSecond = y.replace('%', '');
let valueLimit = 100 - parseInt(withoutPercentage);
if (parseInt(withoutPercentage) + parseInt(withoutPercentageSecond) < 101) {
setLimitSecond(valueLimit);
}
}
function rangeSetterSecond(value) {
setSecondRange(parseInt(value) + '%');
let x = range;
let y = secondRange;
let withoutPercentage = x.replace('%', '');
let withoutPercentageSecond = y.replace('%', '');
let valueLimit = 100 - parseInt(withoutPercentageSecond);
if (parseInt(withoutPercentage) + parseInt(withoutPercentageSecond) < 101) {
setLimit(valueLimit);
}
}
return (
<View>
<Text>{range}</Text>
<Slider
minimumValue={0}
value={equalValueSplit}
maximumValue={100}
upperLimit={limit}
onValueChange={value => rangeSetter(value)}
/>
<Text>{secondRange}</Text>
<Slider
minimumValue={0}
value={equalValueSplit}
maximumValue={100}
upperLimit={limitSecond}
onValueChange={value => rangeSetterSecond(value)}
/>
</View>
);
};
export default SplitBillPage;
Now I'm confused on how to create the logic when the number increases above 2. Here I've used 1 states for each user which are limit and limitSecond, but this doesnt seem efficient when I've 10 users and me creating an individual state for each of them and the using state1 +state2 + ... <101.
So I need a way to solve this logic when the number increases from 2.

Getting infinity loop while checking factors of a number in while loop

I am struggling with infinite loop problem while Array exercise implementation which needs to be done with Java Script functional way:
I have a code which creates an array and fills its values with numbers which fulfil condition:
Each array element has a value,
which we draw from the range <100, 200> until the sum of digits is
a number having exactly two dividers, not counting 1 and this one
numbers.
I have a code like below:
const generateNumber = (min, max) =>
Math.floor(Math.random() * (max - min + 1)) + Math.floor(min);
const unities = number => number % 10;
const hundreds = number => Math.floor((number % 1000) / 100);
const tens = number => Math.floor((number % 100) / 10);
const sumDigits = (number) => unities(number) + hundreds(number) + tens(number);
const countNumberFactors = number => Array
.from(Array(number + 1), (_, i) => i)
.filter(i => number % i === 0)
.slice(1, -1)
.length;
const generateNumberUntilConditionNotAchieve = (min, max) => {
let number = generateNumber(min, max);
const digitsSum = sumDigits(number);
while (countNumberFactors(digitsSum) === 2) {
number = generateNumber(min, max)
}
return number;
}
const generateArray = (minArrSize, maxArrSize, minItemValue, maxItemValue) =>
Array(generateNumber(minArrSize, maxArrSize))
.fill(0)
.map(
() => generateNumberUntilConditionNotAchieve(minItemValue,
maxItemValue));
const main = () => {
const generatedArray = generateArray(1, 5, 100, 200);
console.log("Array -> " + generatedArray);
}
main();
For small minArraySize and maxArraySize values sometimes I am receiving desirable result but for params like <10, 100> my IDE is freezing. On online editor with pasted above code, I am receiving information about the infinite loop on line:
while (countNumberFactors(digitsSum) === 2)
I tried to investigate a root cause by trial and error but I did not find out a solution. I will be grateful for suggestions on how to solve the above infinite loop problem.
You are changing number but checking digitsSum. All you need to do to fix this is add digitsSum = sumDigits(number) in the while loop. e.g.
const generateNumberUntilConditionNotAchieve = (min, max) => {
let number = generateNumber(min, max);
const digitsSum = sumDigits(number);
while (countNumberFactors(digitsSum) === 2) {
number = generateNumber(min, max);
digitsSum = sumDigits(number);
}
return number;
}

Compounding interest monthly with a deposit

I want to compound interest on a weekly/fortnightly/monthly/annual basis.
I also want an option to have a deposit amount that can be added in.
I have already tried the standard formula of calculating the final amount accrued, as seen here:
(source: gstatic.com)
For example here is my method for calculating the interest compounding weekly:
function calculateWeekly(state: any) {
const { savings, deposit ,interest, timePeriodSelector, timePeriodLength } = state;
let numberOfYears = 0;
if (timePeriodSelector === "weekly") {
numberOfYears = timePeriodLength / weeksInAYear;
} else if (timePeriodSelector === "fortnightly") {
numberOfYears = (timePeriodLength / weeksInAYear) * 2;
} else if (timePeriodSelector === "monthly") {
numberOfYears = (timePeriodLength / weeksInAYear) * weeksInAMonth;
} else if (timePeriodSelector === "annually") {
numberOfYears = (timePeriodLength / weeksInAYear) * weeksInAYear;
}
const weeklyRate = interest / 100 / weeksInAYear;
const lengthOfCompunding = numberOfYears * weeksInAYear;
let startingFigure = parseInt(savings) + parseInt(deposit);
//total gets added on for every time cycle of week
let total =
(startingFigure * (Math.pow(1 + weeklyRate, lengthOfCompunding) - 1)) / weeklyRate;
return roundToTwoDP(total);
}
The issue with the above code is that the deposit gets added into the calculation every time the interest accrues. So a deposit of $10 weekly for 10 weeks will actually get added up to $100.
I attempted a method to accrue the interest using a loop for each week here:
// loops how many times to compound the interest
for(let i = numberOfYears - (1/weeksInAYear); i > 0; i-= (1/weeksInAYear)){
let interestGained = (total * (Math.pow((1 + weeklyRate), lengthOfCompunding))) - total;
total += interestGained + savings;
}
Thanks for any help!
This should do what you want:
const range = (min, max) => {
const size = 1 + max - min
return [...Array(size).keys()].map(n => n + min)
}
const weeksInAYear = 52
const addWeeklyInterest = interestRatePerWeek => (savings, _) => savings + savings * interestRatePerWeek
const calculateTotal = (savings, numberOfYears, interestRatePerWeek) => {
const numberOfWeeks = numberOfYears * weeksInAYear
return range(1, numberOfWeeks).reduce(addWeeklyInterest(interestRatePerWeek), savings)
}
console.log(calculateTotal(1000.00, 1, 0.02))
Output is 2800.328185448178. You might want to round that for display purposes, but also keep in mind that if accuracy is important, you can't use floating-point numbers.

Attempting to push into array gives error in angular6

I want to sort the array and to store the fetched values into a new array for print. I tried with push() but there is an error is occurring and shows that" Cannot read property 'push' of undefined".
`
this.dataService.userprofile().subscribe((data:any) => {
let profile:any[]=data.profiles;
for(let index=0;index<profile.length;index++) {
const element = profile[index];
const today: number = Date.now();
var b = Math.abs(today - Date.parse(element["dob"]));
element["dob"] = Math.floor(b / (1000 * 3600 * 24 * 365.25));
if (element["active"]=="N"){
this.row.push(element);
}}
this.rowData = this.row;//ag-grid row
console.log(this.rowData)
})
`
Instead of using for loop that it is hard to read and maintain you better use Array.prototype.reduce() and using the dot notation
Also notice that in TypeScript you should avoid using type any
Code:
this.dataService.userprofile().subscribe((data: any) => {
this.rowData = data.profiles.reduce((acc, element) => {
const b = Math.abs(today - Date.parse(element.dob));
element.dob = Math.floor(b / (1000 * 3600 * 24 * 365.25));
return element.active == 'N' ? [...acc, element] : acc;
}, []);
console.log(this.rowData)
});
Declare row variable before for loop.
this.dataService.userprofile().subscribe((data:any) => {
let profile:any[]=data.profiles;
let row = [];
for(let index=0;index<profile.length;index++) {
const element = profile[index];
const today: number = Date.now();
var b = Math.abs(today - Date.parse(element["dob"]));
element["dob"] = Math.floor(b / (1000 * 3600 * 24 * 365.25));
if (element["active"]=="N"){
row.push(element);
}}
this.rowData = row;//ag-grid row
console.log(this.rowData)
})

Categories