Undefined function with javascripts - javascript

I'm writing a small 'quote calculator'. I want to print the summary to the browser with innerHTML, but I'm still getting "undefined" instead of the price. But in my console.log everything works fine, I can console.log the variable price and get the expected result.
//Variables
const form = document.getElementById('request-quote');
const html = new HTMLUI();
//Event Listeners
eventListeners();
function eventListeners() {
document.addEventListener('DOMContentLoaded', function() {
//Create the <option> for the years
html.displayYears();
});
//when the form is submitted
form.addEventListener('submit', function(e) {
e.preventDefault();
//get values from the form
const make = document.getElementById('make').value;
const year = document.getElementById('year').value;
//Read the radio buttons
const level =
document.querySelector('input[name="level"]:checked').value;
// Validation
if (make === '' || year === '' || level === '') {
html.displayErrors('All fields are mendatory')
} else {
//Make the quotation
const insurance = new Insurance(make, year, level);
const price = insurance.calculateQuotation(insurance);
//print
html.showResults(price);
}
});
}
// Create another prototype with for the object HTMLUI. to print Errors
//Object
// Everything related to the calculation and quotation
function Insurance(make, year, level) {
this.make = make;
this.year = year;
this.level = level;
}
//calculation
Insurance.prototype.calculateQuotation = function(insurance) {
let price;
const base = 2000;
//get make
const make = insurance.make;
/**
1. america: 15
2. Asia : 5
3. europia: 35
*/
switch (make) {
case '1':
price = base * 1.15;
break
case '2':
price = base * 1.05;
break
case '3':
price = base * 1.35;
break
}
//get level
const level = insurance.level;
price = this.calculateLevel(price, level);
//get year
const year = insurance.year;
const difference = this.getYearDifference(year);
price = price - ((difference * 3) * price) / 100;
console.log(price);
}
//return difference between years
Insurance.prototype.getYearDifference = function(year) {
return new Date().getFullYear() - year;
// each year the cost must be 3% cheaper
}
//add value based on level
Insurance.prototype.calculateLevel = function(price, level) {
//basic increase 30%
//complete increases 50%
if (level === 'basic') {
price = price * 1.30;
} else {
price = price * 1.50;
}
return price;
}
function HTMLUI() {}
//display the latest 20 years in the select
HTMLUI.prototype.displayYears = function() {
//Max & minimum years
const max = new Date().getFullYear();
min = max - 20;
//Generate the list
const selectYears = document.getElementById('year');
//print the values
for (let i = max; i >= min; i--) {
const option = document.createElement('option')
option.value = i;
option.textContent = i;
selectYears.appendChild(option);
}
}
//Print Error, by creating a prototype
HTMLUI.prototype.displayErrors = function(message) {
//create div
const div = document.createElement('div');
div.classList = 'error';
//insert message
div.innerText = `
<p>${message}</p>
`;
form.insertBefore(div, document.querySelector('.form-group'));
//Remove the error
setTimeout(function() {
document.querySelector('.error').remove();
}, 3000);
}
HTMLUI.prototype.showResults = function(price) {
//print result
const result = document.getElementById('result');
//create a div with the result
const div = document.createElement('div');
//insert the result
div.innerHTML = `
<p class="total">Total: $ ${price}</p>
`;
//insert into html
result.appendChild(div)
}
I am expecting to print the value of the variable price( which will actually be the price) but I'm getting "undefined" while trying to print the price

You need to add in a return statement to the calculateQuotation function. Here's why, in case it helps.
The reason you're getting undefined is because the price variable is never being given a value.
On this line:
const price = insurance.calculateQuotation(insurance);
price is getting whatever the calculateQuotation function sends back with a return statement. However, in that function you're just filling a price variable which exists only in the context of that function. To make this work, I believe you need to add in a return statement at the end of the calculateQuotation function like so:
Insurance.prototype.calculateQuotation = function(insurance) {
let price;
const base = 2000;
//get make
const make = insurance.make;
/**
1. america: 15
2. Asia : 5
3. europia: 35
*/
switch (make) {
case '1':
price = base * 1.15;
break
case '2':
price = base * 1.05;
break
case '3':
price = base * 1.35;
break
}
//get level
const level = insurance.level;
price = this.calculateLevel(price, level);
//get year
const year = insurance.year;
const difference = this.getYearDifference(year);
price = price - ((difference * 3) * price) / 100;
console.log(price);
return price; // Added this in
}

It shows undefined cause you never returned a result. You need to return the 'price' variable to fix it.
...
const difference = this.getYearDifference(year);
price = price - ((difference * 3) * price) / 100;
console.log(price);
return price;
}

Related

How can I remember a past value in setInterval?

I have this function that continually generates two random numbers ranging from 0 to 7. These two numbers correspond to an id in my DOM.
How do I ensure that the next interval doesn't give the same two numbers in the same order as the last interval (in other words, the giving the same id as the LAST interval)?
If it is the case that they are the same, how do I skip this interval and go on to the next without it waiting for the interval time?
function chooserandomtile() {
cycle = setInterval(() => {
let i_random = Math.floor(Math.random() * 8);
let j_random = Math.floor(Math.random() * 8);
var id = i_random + ',' + j_random;
var target = document.getElementById(id);
if (target.classList.contains('target') || target.contains(player)) {
} else {
target.classList.add('target');
}
console.log(id);
console.log(document.getElementById(id));
}, interval);
Just declare a variable that will persist outside the scope of your method, and set it to keep track of the previous value. If your random logic produces the same ID as the previous time, try again until it gives you a different value.
function chooserandomtile() {
let lastId;
cycle = setInterval(() => {
let id;
do {
let i_random = Math.floor(Math.random() * 8);
let j_random = Math.floor(Math.random() * 8);
id = i_random + ',' + j_random;
} while (id === lastId)
lastId = id;
var target = document.getElementById(id);
if (target.classList.contains('target') || target.contains(player)) {
} else {
target.classList.add('target');
}
console.log(id);
console.log(document.getElementById(id));
}, interval);

How to link a slider and checkbox to a counter?

I am new in JavaScript. I am trying to link a slider and checkbox to a counter. The slider should increase the counter's value depending on the range. And then the checkboxes have fixes values depending on the users(the slider's value are users, I will explain later) that they should add to the counter if it is checked or not.
var slider = document.querySelector('#myRange'); //Input
var output = document.querySelector("#value-range"); //Output
let rangeValue = document.querySelector('#final-price'); //Counter
const boxesContainer = document.querySelector('.price-boxes__container'); //Checkboxes
I created an event for the checkboxes, so when you click on it, adds the value.
boxesContainer.onchange = function(e) {
if (e.target.classList.contains('checkbox')){
const price = parseInt(e.target.getAttribute('value'))
if (e.target.checked === true) {
total += price;
} else {
total -= price;
}
rangeValue.innerHTML = total
}
}
And I created another event for the slider as well.
slider.oninput = function () {
let value = slider.value;
userPrice(value)
output.style.left = (value/2.88);
output.classList.add("show");
rangeValue.innerHTML = prices[value-25];
function userPrice (value) {
if (value == 25) {
output.innerHTML = '6 €p'
} else {
output.textContent = `${prices[value-25] - prices[value-26]} €p`;
}
}
}
The slider has min 25, max 1000, step = 1, value = 25. Each step is one user. I created an array that has the price depending on the slider's value. Between 26-50 users 6€ per user, 51-250 4€/p, 251-500 3€/p and 501-1000 2€/p. Therefore, I thought the easy way was to create an array and use the slider's value to sent the price to the counter.
const range = (start, stop, step) => Array.from({ length: (stop - start) / step + 1}, (_, i) => start + (i * step));
let rangePrices = range(25, 1000, 1);
const prices = [];
rangePrices.forEach((rangeValue, i)=> {
if(rangeValue === 25) {
prices.push(299)
} else if (rangeValue < 51) {
prices.push(prices[i-1] + 6)
} else if (rangeValue < 251){
prices.push(prices[i-1] + 4)
} else if (rangeValue < 501) {
prices.push(prices[i-1] + 3)
} else {
prices.push(prices[i-1] + 2)
}
});
But at the end, when I click on the checkboxes the counter adds the checkboxes' values, but it resets. I know that I have two rangeValue.innerHTML and is due to this that it does not work, but I do not know how to fix it...
As I said at the beginning the checkbox depends on the slider value. Between 26-50 0.7€/p.u., 51-250 0.5€/p.u., 251-500 0.4€/p.u. and 501-1000 0.3€/p.u.. Therefore, so the checkboxes are related to the slider. I do not know how to link both functions either. Finally say that there are 2 more checkboxes.
It would be great if someone could help me!
https://jsfiddle.net/NilAngelats/wq7tjh8c/
This is what I did:
let total = 0;
boxesContainer.onchange = function(e) {
...
rangeValue.innerHTML = prices[slider.value - 25] + total
}
slider.oninput = function() {
...
rangeValue.innerHTML = prices[value - 25] + total;
}
And move userPrice function out of the slider.oninput function so it's only declared once and not every time you move the slider.

Increase a number based on Date or Interval javascript (and keep it after refresh page)

I'm struggling for while trying to figure out how to increase a number based on a Date or based on a time (Using setInterval).
I don't know which option is easier. I made it by using setInterval:
HTML
<p class="counter"></p>
JS
let tickets = 35000;
const counter = document.querySelector('.counter');
let interval = setInterval(function(){
console.log(tickets);
if (tickets >= 60000) {
var textSoldOut = `<p>¡Todo vendido!</p>`;
counter.innerHTML = textSoldOut;
console.log("Sold out");
clearInterval(interval);
}else{
var text = `¡${tickets} tickets Sold!`;
contador.innerHTML = text;
console.log(text)
}
const random = Math.floor(Math.random()*(200-100+1)+100);
tickets += random;
}, 10000);
The thing is every time the page is refreshed the counter starts from 35000 again. I am trying to figure out how to storage the var tickets. I guess this would be made by using localStorage, but since I am a beginner in JS, I am not able to do it.
Other option would be by checking the date, and based on that, show a number:
function date() {
var d = new Date();
var month = d.getMonth();
var day = d.getDate();
const counter = document.querySelector('.contador');
const random = Math.floor(Math.random()*(200-100+1)+100);
for (let i = 350000; i <= 60000 ; i++) {
if (month == 0 & day == 28) {
var sum = i + random;
document.getElementById("contador").innerHTML = suma;
}else if (mes == 0 & dia == 30) {
...
} else if (...){
...
}
}
document.getElementById("dia").innerHTML = dia;
document.getElementById("mes").innerHTML = mes;
}
fecha();
Could someone help me out to reach the result?
I would really appreciate it
The Storage object accessible via the localStorage property offers two methods to save or retrieve data: setItem and getItem().
Usage is quite simple. If you want to save the numbers of tickets into a myTickets key on localStorage you have to do it like this:
localStorage.setItem("myTickets", tickets);
To retrieve that data later on:
localStorage.getItem("myTickets");
You just have to make sure to update the myTickets key on localStorage as you increase the number of tickets inside the setinterval callback function.
let tickets = 35000;
if (localStorage.getItem("myTickets") == null) {
localStorage.setItem("myTickets", tickets);
} else {
tickets = localStorage.getItem("myTickets");
}
const counter = document.querySelector('.counter');
let interval = setInterval(function() {
console.log(tickets);
if (tickets >= 60000) {
var textSoldOut = `<p>¡Todo vendido!</p>`;
counter.innerHTML = textSoldOut;
console.log("Sold out");
clearInterval(interval);
} else {
var text = `¡${tickets} tickets Sold!`;
console.log(text)
}
const random = Math.floor(Math.random() * (200 - 100 + 1) + 100);
tickets += random;
localStorage.setItem("myTickets", tickets);
}, 10000);

Getting previous objects value in current object

I am using a dataset that contains around 65k data. I am mapping over the dataset multiple times to massage the dataset. After obtaining the dataset in the required format, I am using map to do some computations with the price of the current item. But, whenever I return the current object, it contains the computation data of the previous object.
Whenever I log the data, it always shows the current object and the computations based on the current object. But, the returned object contains a previous object's data. Here is the route:
const {priceBands} = require('../utils/profitComputations');
let profitArray = [];
//calculating the price bands
profitArray = _.map(nfoArray, item=>{
console.log(item.cmp);
//returns the current market price; getting the correct value here
let priceBandVar = priceBands(Number(item.cmp));
console.log(priceBandVar);
//applying some algorithms; getting the correct value here
return {item: item.cmp, profitBand: priceBandVar};
//Here I find a mismatch between the parameter and the calculations
});
Here is the priceBands function in my 'utils/profitComputations':
const _ = require('lodash');
const priceBandInterval = {'-4':0, '-3':0, '-2':0, '-1':0, '0floor':0,'0ceil':0,'1':0, '2':0, '3':0, '4':0};
let priceBands = {};
module.exports = {
priceBands: function(price){
let factor = 0;
if(price>=10000){
factor = 100;
}else if (price>=1000 && price<10000){
factor = 50;
}else if (price>=500 && price<1000){
factor = 25;
}else if (price>=100 && price<500){
factor = 10;
}else if(price>=25 && price<100){
factor = 2;
}else{
factor = 0.5;
}
let priceCeil, priceFloor;
if((price%factor) == 0){
priceCeil = price + factor;
priceFloor = price - factor;
} else {
const remainder = price%factor;
priceCeil = price - remainder + factor;
priceFloor = price - remainder;
}
_.map(Object.keys(priceBandInterval), item=>{
if(parseInt(item)>0){
priceBands[item] = (parseInt(item)*factor) + priceCeil;
} else if (parseInt(item)<0){
priceBands[item] = (parseInt(item)*factor) + priceFloor;
} else {
priceBands['0floor'] = priceFloor;
priceBands['0ceil'] = priceCeil;
}
});
return priceBands;
}
}
I would appreciate if someone can share some valuable insights on what I am missing.
You must clone the variable priceBandVar because javaScript variables are called by reference. The following code is your answer:
profitArray = _.map(nfoArray, item => {
console.log(item.cmp);
//returns the current market price; getting the correct value here
let priceBandVar = priceBands(Number(item.cmp));
console.log(priceBandVar);
//applying some algorithms; getting the correct value here
return {
item: item.cmp,
profitBand: clone(priceBandVar)
};
//Here I find a mismatch between the parameter and the calculations
});
function clone(o) {
var ret = {};
Object.keys(o).forEach(function(val) {
ret[val] = o[val];
});
return ret;
}

Generate "Unique" 5 digits ID with javascript (99999 combinations) in random order

I want to generate an Unique 5 digits ID + 784 at the begining, the constraint, I can execute the script only one time, and I have to avoid the first 100 numbers so It can't be 00100 and lower. Since I use timestamp and I can execute only my script one time how I can handle this ?
I did this it's maybe dumb but at least I tried.
ConcatedID();
function ConcatedID()
{
var uniqID = checkProtectedRange();
if (checkProtectedRange())
{
var BarcodeID = 784 + uniqID;
return BarcodeID;
}
else
checkProtectedRange();
}
function checkProtectedRange()
{
var uniqueID = GenerateUniqueID();
var checkRange = uniqueID.substr(uniqueID.length - 3);
var checkRangeINT = parseInt(checkRange);
if (checkRangeINT <= 100)
return (false);
else
return (true);
}
function GenerateUniqueID()
{
var lengthID = 5;
var timestamp = + new Date();
var ts = timestamp.toString();
var parts = ts.split("").reverse();
var id = "";
var min = 0;
var max = parts.length -1;
for (var i = 0; i < lengthID; ++i)
{
var index = Math.floor(Math.random() * (max - min + 1)) + min;
id += parts[index];
}
gs.log('Generate ID ' + id);
return id;
}
Without being able to track previously used IDs, you're left with chance to prevent duplicates. Your shenanigans with Date doesn't really change that. See the birthday problem.
Given that, just follow the most straight-forward method: Generate a random string consisting of five digits.
function GenerateUniqueID() {
return ('0000'+(Math.random() * (100000 - 101) + 101)|0).slice(-5);
}
Or, if you want just the final integer with constraints applied:
function GenerateUniqueID() {
return (Math.random() * (78500000 - 78400101) + 78400101)|0;
}

Categories