destructuring with the same keys in JavaScrypt - javascript

I can get to limitfrom in the second case if I rename limitfrom to limitfrom2, but I don't understand how to get to the value without renaming the key. Maybe I'm doing the wrong thing about the destructuring itself.
create an object
const vedPlus = {
transferLegal: {
stageOne: {
limitfrom: 0,
limitUpTo: 60,
commission: 0
},
stageTwo: {
limitfrom2: 60,
limitUpTo2: 1000,
commission2: 29
},
}
then I do the destructuring in 4 steps.
const {transferLegal} = vedPlus
const {stageOne, stageTwo} = transferLegal
const {limitfrom, limitUpTo, commission} = stageOne
const {limitfrom2, limitUpTo2, commission2} = stageTwo
Create a function
function calc (i) {
if (i >= limitfrom && i <= limitUpTo) {
return i * commission
} else if (i >= limitfrom2 && i <= limitUpTo2) {
return i * commission2
} else {
console.log('error')
}
result
const price = 71
console.log(calc(price))
Is there a way to get to the value without renaming the key?

You can use the same property names for both inner objects, and then assign new unique names when destructuring to prevent conflicts, using const { prop: newName } = source syntax.
It may not produce the most readable code, but at least it can be done.
Demo:
const vedPlus = {
transferLegal: {
stageOne: { limitfrom: 0, limitUpTo: 60, commission: 0 },
stageTwo: { limitfrom: 60, limitUpTo: 1000, commission: 29 },
}
}
const { transferLegal } = vedPlus;
const { stageOne, stageTwo } = transferLegal;
const { limitfrom, limitUpTo, commission } = stageOne;
const { limitfrom: limitfrom2, limitUpTo: limitUpTo2, commission: commission2 } = stageTwo;
console.log(limitfrom, limitUpTo, commission);
console.log(limitfrom2, limitUpTo2, commission2);

Yes. But certainly not like this:
const {limitfrom, limitUpTo, commission} = stageOne;
const {limitfrom, limitUpTo, commission} = stageTwo;
Because you'd be re-declaring the same variables in the same scope. After these two lines, if you were to refer to the variable limitfrom, which one would you expect it to be and why?
If the keys have the same name, that's fine as long as they are unique within their context. In this case within their individual objects. You can use those objects to reference them:
const {stageOne, stageTwo} = transferLegal;
//...
if (i >= stageOne.limitfrom && i <= stageOne.limitUpTo) {
return i * stageOne.commission
} else if (i >= stageTwo.limitfrom && i <= stageTwo.limitUpTo) {
return i * stageTwo.commission
}
Basically, absolutely everything doesn't have to be destructured into its own variable with a single value. Objects exist for a reason, use them.

If you want to keep the data (vedPlus) as the same structure you can do the renaming while you are destructuring
const vedPlus = {
transferLegal: {
stageOne: {
limitfrom: 0,
limitUpTo: 60,
commission: 0
},
stageTwo: {
limitfrom: 60,
limitUpTo: 1000,
commission: 29
}
}
}
const {
transferLegal: {
stageOne: {
limitfrom,
limitUpTo,
commission
},
stageTwo: {
limitfrom: limitfrom2,
limitUpTo: limitUpTo2,
commission: commission2
}
}
} = vedPlus
function calc(i) {
if (i >= limitfrom && i <= limitUpTo) {
return i * commission
} else if (i >= limitfrom2 && i <= limitUpTo2) {
return i * commission2
} else {
console.log('error')
}
}
const price = 71
console.log(calc(price))

if the final goal is a simple calculation, then the use of the destructuring mechanism does not bring anything useful
const vedPlus =
{ transferLegal:
{ stageOne: { limitfrom: 0, limitUpTo: 60, commission: 0 }
, stageTwo: { limitfrom: 60, limitUpTo: 1000, commission: 29 }
} }
function calc(i)
{
let obj = vedPlus.transferLegal
for (let stage in obj)
{
if (obj[stage].limitfrom <= i && i <= obj[stage].limitUpTo)
return obj[stage].commission *i
}
throw `error: ${i} is out of range!`
}
console.log( '50 =>', calc(50) )
console.log( '500 =>', calc(500) )
console.log( '5000 =>', calc(5000) )

Related

Writing dynamic conditional statement in javascript

I am creating a multistep form where a value (or multiples) of a form field determine whether a subsequent step is shown.
For example, the data I am receiving looks like:
{
cardConditional:
lessThan: 75
show: true
when: "fieldKeyHere"
...
}
This is basically telling me, if the when is lessThan 75 show the step. it can return greaterThan or eq as well which i've accounted for in the code below. My question is how can i take that information and construct a function to return true or false depending on that? I guess im stuck on how to string together that conditional with the string from getMathSymbol.
Here's what i have so far:
const checkStepConditional = (step) => {
const getMathSymbol = () => {
if (step.cardConditional.eq) return "===";
else if (step.cardConditional.lessThan) return "<";
else if (step.cardConditional.greaterThan) return ">";
};
if (step.cardConditional) {
const conditionalFieldKey = step.cardConditional.when;
return form.values[conditionalFieldKey] <-- stuck here
} else {
return true;
}
};
You can create an object keyed by the conditions which each implements the method necessary for the comparison, and use an every() on the conditions that exist in your cardConditional object to check of all conditions match.
const checkStepConditional = (form, step) => {
const checkIf = {
eq: (a, b) => a === b,
lessThan: (a, b) => a < b,
greaterThan: (a, b) => a > b,
}
if (step.cardConditional) {
const cardCond = step.cardConditional;
const field = form.values[cardCond.when];
const conditions = Object.keys(checkIf).filter(k => k in cardCond);
return conditions.every(condition => checkIf[condition](field, cardCond[condition]))
? cardCond.show
: !cardCond.show
}
};
const
card = { cardConditional: { lessThan: 75, show: true, when: "fieldKeyHere", } },
form = { values: { "fieldKeyHere": 60 } };
console.log(checkStepConditional(form, card));
// 60 < 75 ? show: true
const
card1 = { cardConditional: { lessThan: 75, greaterThan: 60, show: true, when: "fieldKeyHere", } },
form1 = { values: { "fieldKeyHere": 65 } };
console.log(checkStepConditional(form1, card1));
// 65 < 75 && 65 > 60 ? show: true
const
card2 = { cardConditional: { lessThan: 75, greaterThan: 60, show: true, when: "fieldKeyHere", } },
form2 = { values: { "fieldKeyHere": 55 } };
console.log(checkStepConditional(form2, card2));
// 55 < 75 && 55 > 60 ? show: false

JavaScript trying to find the highest sales made in a particular branch

I am trying to create a class to find out the branch made the most in revenue.I believe, I need to sum all branch across multiple days and identify which branch had the highest sales overall. But I am kinda lost. Would anyone be able to help me? Thanks for the help
class SalesItem {
constructor(branch, totalSales, date) {
this.branch = branch;
this.totalSales = totalSales;
this.date = date
}
}
function CalculateBestBranch(sales) {
var branchSales = { key: "", value: 0 };
// TODO: order branchSales by value, highest first
// TODO: return the key of the highest value
const highestValue = 0;
return highestValue;
}
class SalesItem {
constructor(branch, totalSales, date) {
this.branch = branch;
this.totalSales = totalSales;
this.date = date;
}
}
const sales = [
new SalesItem('branch-1', 60, '2022-01-26'),
new SalesItem('branch-2', 90, '2022-01-26'),
new SalesItem('branch-1', 20, '2022-01-27'),
new SalesItem('branch-2', 30, '2022-01-27'),
];
function calculateBestBranch(sales) {
const branchSales = [];
sales.forEach((sale) => {
if (!branchSales.find((e) => e.key === sale.branch)) {
branchSales.push({ key: sale.branch, value: sale.totalSales });
} else {
let i = branchSales.findIndex((e) => e.key == sale.branch);
branchSales[i].value += sale.totalSales;
}
});
const sortedBranchSales = branchSales.sort((a, b) => b.value - a.value);
return sortedBranchSales[0];
}
calculateBestBranch(sales); // { key: 'branch-2', value: 120 }

Randomly push names into one of two arrays

I have an object with two arrays (_licky, _unlucky). and methods that randomly push names into one of the two arrays. But my code does not work for some reason... What is wrong with my code?
const luckGame = {
_lucky: [],
_unlucky: [],
pushGamer(name) {
return name;
},
getRandomNumber (random) {
return random = Math.floor(Math.random() * 2);
},
pushGamerIntoArray () {
return {
if (this.getRandomNumber() === 0 ) {
this._lucky.push(this.pushGamer());
} else {
this._unlucky.push(this.pushGamer());
}
};
},
};
this.pushGamer('John');
this.pushGamer('Nick');
this.pushGamer('Maria');
this.pushGamer('Sarah');
this.pushGamer('Ron');
this.pushGamer('Lisa');
console.log(luckGame._lucky);
console.log(luckGame._unlucky);
I fixed it. Now it works. thank you all!!
const luckGame = {
_lucky: [],
_unlucky: [],
getRandomNumber (random) {
return random = Math.floor(Math.random() * 2);
},
pushGamerIntoArray (name) {
if (this.getRandomNumber() === 0 ) {
return this._lucky.push(name);
} else {
return this._unlucky.push(name);
}
},
};
luckGame.pushGamerIntoArray('John');
console.log(luckGame._lucky);
console.log(luckGame._unlucky);
There were a few small errors on your part. I have rewritten it in a class variant. It works, but I would still improve a few things. You can test it a bit.
const luckyGame = class {
constructor() {
this._lucky = [],
this._unlucky = []
}
pushGamer(name) {
this.pushGamerIntoArray(name)
}
getRandomNumber (random)
{
return random = Math.floor(Math.random() * 2);
}
pushGamerIntoArray (newGamerName)
{
if (this.getRandomNumber() === 0 ) {
this._lucky.push(newGamerName)
} else {
this._unlucky.push(newGamerName)
}
}
getLuckies () {
return this._lucky
}
getUnluckies () {
return this._unlucky
}
}
let luckygame = new luckyGame()
luckygame.pushGamer('John');
luckygame.pushGamer('Nick');
luckygame.pushGamer('Maria');
luckygame.pushGamer('Sarah');
luckygame.pushGamer('Ron');
luckygame.pushGamer('Lisa');
luckygame.pushGamer('John');
console.log(luckygame.getLuckies());
console.log(luckygame.getUnluckies());

How to manage concurrency in client JS?

I faced some issues regarding concurrency issue in client side JS. There are two lines of code which sends request using axios. But the following code is run before the callback function for axios request is completed.
Any way to solve this concurrency problem? As far as I know async/await is only used in backend JS like Node.JS
var declaration:
var chartGroundTank = echarts.init(document.getElementById('chart-ground-tank'));
var chartElevatedTank = echarts.init(document.getElementById('chart-elevated-tank'));
var optionChartGroundTank = {
series: {
type: 'liquidFill',
data: [{
name: '',
value: 0,
// waveAnimation: false,
amplitude: '4%',
itemStyle: {
color: '',
},
}]
}
};
var optionChartElevatedTank = {
series: {
type: 'liquidFill',
data: [{
name: "",
value: 0,
itemStyle: {
color: ''
},
// waveAnimation: false,
amplitude: '4%',
}]
}
};
function call:
axios
.get("/api/v1/firstAPI")
.then(function (response) {
const groundTankData = response.data.sensor1;
const elevatedTankData = response.data.sensor2;
setWaterTankColor(groundTankData, optionChartGroundTank, 'gnd'); // the values are
setWaterTankColor(elevatedTankData, optionChartElevatedTank, 'elv'); // set slower
chartGroundTank.setOption(optionChartGroundTank); // this two lines
chartElevatedTank.setOption(optionChartElevatedTank); // will run earlier
....
)};
function definition:
function setWaterTankColor(waterLevel, tankType) {
axios.get("/api/v1/metrics/getData", {
...config,
})
.then((response) => {
var { sensor1Info1, sensor1Info2, sensor2Info1, sensor2Info2 } = response.data;
if (tankType == 'gnd') {
var color = waterLevel < sensor1Info1 / 100 || waterLevel > sensor1Info2 / 100 ? optionChartGroundTank.series.data[0].itemStyle.color = ["red"] : optionChartGroundTank.series.data[0].itemStyle.color = ["#2f529a"];
}
else {
var color = waterLevel < sensor2Info1 / 100 || waterLevel > sensor2Info2 / 100 ? optionChartElevatedTank.series.data[0].itemStyle.color = ["red"] : optionChartElevatedTank.series.data[0].itemStyle.color = ["#2f529a"];
}
});
}
You should return the promise, you have in setWaterTankColor, then you can set the option after the callback completed.
function setWaterTankColor(waterLevel, tankType) {
return axios.get("/api/v1/metrics/getData", {
...config,
})
.then((response) => {
var { sensor1Info1, sensor1Info2, sensor2Info1, sensor2Info2 } = response.data;
if (tankType == 'gnd') {
var color = waterLevel < sensor1Info1 / 100 || waterLevel > sensor1Info2 / 100 ? optionChartGroundTank.series.data[0].itemStyle.color = ["red"] : optionChartGroundTank.series.data[0].itemStyle.color = ["#2f529a"];
}
else {
var color = waterLevel < sensor2Info1 / 100 || waterLevel > sensor2Info2 / 100 ? optionChartElevatedTank.series.data[0].itemStyle.color = ["red"] : optionChartElevatedTank.series.data[0].itemStyle.color = ["#2f529a"];
}
});
}
Then you can use the function like this:
axios
.get("/api/v1/firstAPI")
.then(function (response) {
const groundTankData = response.data.sensor1;
const elevatedTankData = response.data.sensor2;
setWaterTankColor(groundTankData, optionChartGroundTank, 'gnd').then(function() { chartGroundTank.setOption(optionChartGroundTank); });
setWaterTankColor(elevatedTankData, optionChartElevatedTank, 'elv').then(function() { chartElevatedTank.setOption(optionChartElevatedTank); });
....
)};
That two lines of codes run earlier because they are sync functions.
In order to make them run later, you can await for the the function setWaterTankColor first.
You can use async/await in your case. I also add trycatch to catch error from API call.
(async function run() {
try {
const response = await axios.get("/api/v1/firstAPI");
const groundTankData = response.data.sensor1;
const elevatedTankData = response.data.sensor2;
await setWaterTankColor(groundTankData, optionChartGroundTank, "gnd");
await setWaterTankColor(elevatedTankData, optionChartElevatedTank, "elv");
chartGroundTank.setOption(optionChartGroundTank);
chartElevatedTank.setOption(optionChartElevatedTank);
} catch (err) {
console.log(err);
}
})();
async function setWaterTankColor(waterLevel, tankType) {
try {
const response = axios.get("/api/v1/metrics/getData", {
...config,
});
const { sensor1Info1, sensor1Info2, sensor2Info1, sensor2Info2 } =
response.data;
if (tankType == "gnd") {
var color =
waterLevel < sensor1Info1 / 100 || waterLevel > sensor1Info2 / 100
? (optionChartGroundTank.series.data[0].itemStyle.color = ["red"])
: (optionChartGroundTank.series.data[0].itemStyle.color = [
"#2f529a",
]);
} else {
var color =
waterLevel < sensor2Info1 / 100 || waterLevel > sensor2Info2 / 100
? (optionChartElevatedTank.series.data[0].itemStyle.color = ["red"])
: (optionChartElevatedTank.series.data[0].itemStyle.color = [
"#2f529a",
]);
}
} catch (err) {
throw err;
}
}

Javascript: More concise way to reduce/aggregate by key?

This code gives the expected result, but is there a more concise way to achieve the same result? This is simply a matter of curiosity though.
The goal is to have a map representing the total students in each school, as well as a map representing the total teachers in each school.
// Example data
const studentsMap = {
student123: {
teacher: 'teacher123'
},
student456: {
teacher: 'teacher123'
},
student789: {
teacher: 'badID'
},
student000: {}
};
const teachersMap = {
teacher123: {
school: 'school123'
},
teacher456: {
school: 'school123'
},
teacher789: {
school: 'school456'
}
};
const studentsTotalBySchool = Object.keys(studentsMap).reduce((totals, key) => {
const current = studentsMap[key];
if (!teachersMap[current.teacher] || !teachersMap[current.teacher].school) {
return totals;
}
totals[teachersMap[current.teacher].school] = (totals[teachersMap[current.teacher].school] || 0) + 1;
return totals;
}, {});
const teachersTotalBySchool = Object.keys(teachersMap).reduce((totals, key) => {
const current = teachersMap[key];
totals[current.school] = (totals[current.school] || 0) + 1;
return totals;
}, {});
Is there a way to write this more succinctly without sacrificing too much readability?
You can use Object.entries and destructuring like so:
const studentsTotalBySchool = Object.entries(studentsMap).reduce((totals, [key, { teacher }) => {
if (!teachersMap[teacher] || !teachersMap[teacher].school) return totals;
totals[teachersMap[teacher].school] = (totals[teachersMap[teacher].school] || 0) + 1;
return totals;
}, {});
const teachersTotalBySchool = Object.entries(teachersMap).reduce((totals, [key, { school }) => {
totals[school] = (totals[school] || 0) + 1;
return totals;
}, {});
this will get you the same results with much less code
let schools = {
school123: {
teacher123 : {
students: ["student123", "student456"]
},
teacher456 : {
students: ["student789"]
}
},
school456: {
teacher123 : {
students: ["student123", "student456"]
},
teacher456 : {
students: ["student789"]
}
}
};
function findTotal(school, totalOf){
let accumulated = 0;
switch(totalOf){
case "students":
for(let teachers of Object.keys(schools[school])){
accumulated += schools[school][teachers].students.length;
}
break;
case "teachers":
accumulated = Object.keys(schools[school]).length;
}
return accumulated;
}
console.log(findTotal("school123", "students"))
console.log(findTotal("school123", "teachers"))

Categories