I am making a simple inventory app where I get stuck while increasing the stock. If I try to increase stock it's only working for the first element, not any other element, and if I try to increase any other element stock it again increases stock in first element of the array
Only increasing value of the first element of the array
If I choose any other item code it again chooses the first element and increase value in the first element
// Constructor For Products
var item = function(name,itemCode,stock){
this.name = name;
this.itemCode = itemCode;
this.stock = stock;
}
var data = [];
function addItem(name,itemCode,stock){
if (data.map(i => i.itemCode).includes(itemCode)) return alert('you enter a duplicate itemcode'),menu();
var Newitem = new item(name,itemCode,stock);
data.push(Newitem);
}
//Delete item
function delItem(n){
if (data.map(i => i.itemCode).includes(n)){
var getIndex = data.indexOf(n)+1;
data.pop(getIndex);
}else{
alert('This item is not in the database')
}
}
//Increase stock
item.prototype.inc = function(j){
return this.stock = this.stock + j;
}
function incItem(n,val){
if (data.map(i => i.itemCode).includes(n)){
var getIndex = data.indexOf(n)+1;
let lmn = data[getIndex].inc(val);
return lmn;
}else{
alert('This item is not in the database')
}
}
addItem('BlueTee',100,50);
addItem('Yellow tee',101,100);
addItem('BrownTee',102,120);
You are overcomplicating the problem. You can, for example, use the find() to get the first element in the array and then just increment it's stock property by val, something like:
data = [
{ name: "BlueTee", itemCode: 100, stock: 50 },
{ name: "Yellow tee", itemCode: 101, stock: 100 },
{ name: "BrownTee", itemCode: 102, stock: 120 },
];
function incItem(n, val) {
let item = data.find((p) => p.itemCode === n);
if (item) {
item.stock += val;
return item;
} else {
console.log("This item is not in the database");
}
}
console.log(incItem(102, 5));
incItem(666, 10);
If you really learning to learn basic of class, methods. Look for array.find implementation.
Below given code, you can refer as small clean up to your code.
class Item {
constructor(name, itemCode, stock) {
this.name = name;
this.itemCode = itemCode;
this.stock = stock;
this.list = [];
}
inc(n) {
return (this.stock += n);
}
}
class ItemInventory {
constructor() {
this.list = [];
}
addItem(name, itemCode, stock) {
const item = this.list.find((item) => item.itemCode === itemCode);
if (item) return alert("you enter a duplicate itemcode"), menu();
this.list.push(new Item(name, itemCode, stock));
}
findAndInc(n, val) {
const item = this.list.find((item) => item.itemCode === val);
if (item) {
item.inc(n);
return item;
} else {
alert("This item is not in the database");
}
}
}
const inventory = new ItemInventory();
inventory.addItem("BlueTee", 101, 50);
inventory.addItem("Yellow tee", 102, 38);
inventory.addItem("Brown tee", 103, 89);
console.log(inventory.list);
inventory.findAndInc(5, 101);
console.log(inventory.list);
Related
Hey guys I am trying to build a function that counts the number of employees in each store. As you can see I have a class for stores, and a class for employees down below.
class Stores {
constructor(place, employees) {
this.place = place;
this.employees = employees;
}
}
class Employees {
constructor(name) {
this.name = name;
this._EmployeeID = Employees.counter; //ID for the employee
}
get EmployeeID() {
return this._EmployeeID
}
static get counter() {
Employees._counter = (Employees._counter || 0) + 1;
return Employees._counter
}
}
Here I have listed some employees and stored them into lists
//employees
const employee1 = new Employees("Torben")
const employee2 = new Employees("Mike")
const employee3 = new Employees("Rikke")
const employee4 = new Employees("Walid")
const employee5 = new Employees("Jens")
I have tried to build this function that loops over the objects, to count them, however for some reason I am not getting the correct result.
const copenhagenstore = new Stores("Copenhagenstore", {employee1, employee2, employee5})
function countemployees(store) {
var length = 0;
for(var key in store) {
console.log(key)
if(store.hasOwnProperty(key) ) {
++length;
}
}
return length;
};
console.log("the number of employees are: " + countemployees(copenhagenstore))
Below is my output, and as you can see, there should be 3 employees instead of two. I am pretty sure my function needs a bit of rework to account for this, and I was hoping that you guys could help me with that.
//OUTPUT
the number of employees are: 2
Stores {
place: 'Copenhagenstore',
employees: {
employee1: Employees { name: 'Torben', _EmployeeID: 1 },
employee2: Employees { name: 'Mike', _EmployeeID: 2 },
employee5: Employees { name: 'Jens', _EmployeeID: 5 }
}
}
I am getting a type error message when I am trying to remove a
property from a data structure I have created everytime I click to remove
a property it throws this error code " Uncaught TypeError: Cannot read
property 'map' of undefined
at Object.deleteItem (app.js:69)
at HTMLDivElement.ctrlDeleteIitem (app.js:292)
deleteItem # app.js:69
ctrlDeleteIitem # app.js:292"
I am following a JS tutorial and i am currently building a budget app but
I am getting this error message and I am unsure as to why as I believe I
have declared all the relevant variables but I clearly haven't.
I have added comments specifically like this "<-- problem line of code"
and "<-- end of problem code ->" so you can clearly see where the issue is
occurring
I have tried already to add parsentInt method to line 288 to contvert the
string into a number but still I am being told that I have not defined map
at line 69
//budget controller
//function constructor
var budgetController = (function() {
var Expense = function(id,description, value) {
this.id = id,
this.description = description,
this.value = value;
};
var income = function(id,description, value) {
this.id = id,
this.description = description,
this.value = value;
};
var totalCal= function (type){
var sum = 0;
data.items[type].forEach(function(current){
sum += current.value;
});
data.total[type] = sum;
}
var data = {
items: {
exp: [],
inc:[]
},
total: {
exp: 0,
inc: 0
},
budget:0,
percentage: -1
};
return{
addItem(type,des,val){
var newItem, ID;
// create new ID
if (data.items[type].length > 0){
ID = data.items[type][data.items[type].length -1].id + 1;
} else {
ID = 0;
}
// Create new item based on inc or exp type
if (type === 'exp'){
newItem = new Expense(ID,des,val);
} else if (type === 'inc'){
newItem = new income(ID, des, val);
}
// Push it into data structure
data.items[type].push(newItem);
// Return the new element
return newItem;
},
<-- this block of code is generating the error--> deleteItem:
function (type, id) {
var ids, index;
ids = data.items[type].map(function(current) {
return current.id;
});
index = ids.indexOf(id);
if (index !== -1){
data.items[type].splice(index, 1);
}
},
<---end of problem code--->
calculateBudget: function (){
// calculate total income and expenses
totalCal('exp');
totalCal('inc');
// calculate the budget: income - expenses
data.budget = data.total.inc - data.total.exp;
//calculate the percentage of income that we spend
if (data.total.inc > 0) {
data.percentage = Math.round((data.total.exp /
data.total.inc) *100);
} else {
data.percentage = -1;
}
},
getBudget: function () {
return {
budget: data.budget,
income: data.total.inc,
Expense:data.total.exp,
percentage: data.percentage
};
},
testing: function(){
console.log(data);
}
};
})();
//UI controller
var UIController = (function() {
//public function
// private object to store strings to make code more cleaner
var DOMstrings = {
inputType: '.expType',
inputDescription: '.expDescription',
inputValue:'.expValue',
inputBtn: '.plus__btn',
incomeContainer: '.incomeList',
expensesContainer: '.expensesList',
budgetLabel: '.budgetValue',
incomeLabel: '.budgetIncomeValue',
expensesLabel:'.budgetExpensesValue',
percentageLabel:'.budgetExpensesPercentage',
container: '.container'
};
return {
getInput: function () {
return {
type: document.querySelector(DOMstrings.inputType).value, //
will be either inc or exp
description:
document.querySelector(DOMstrings.inputDescription).value,
value: parseFloat
(document.querySelector(DOMstrings.inputValue).value)
};
},
addListItems: function (obj, type){
var html, newHTML, element;
// Create HTML string with placeholder text
if (type === 'inc'){
element = DOMstrings.incomeContainer;
html = '<div class="item clearfix" id="%inc-%"><div
class="item__description">%description%</div><div class="right
clearfix"> <div class="item__value">%value%</div><div
class="item__delete"><button class="item__delete--btn"><i class="ion-
ios-close-outline"></i></button></div></div></div>';
} else if (type === 'exp'){
element = DOMstrings.expensesContainer;
html='<div class="item clearfix" id="exp-%id%"><div
class="item__description">%description%</div><div class="right
clearfix"><div class="item__value">%value%</div><div
class="item__percentage">21%</div><div class="item__delete"><button
class="item__delete--btn"><i class="ion-ios-close-outline"></i>
</button>
</div></div></div>';
}
//replace the placeholder text with some actual data
newHTML = html.replace('%id%', obj.id);
newHTML = newHTML.replace('%description%', obj.description);
newHTML = newHTML.replace('%value%', obj.value);
// insert HTML into DOM
document.querySelector(element).insertAdjacentHTML('beforeend',
newHTML);
},
// method to clear input fields after user types in a value and
presses enter
clearFields: function (){
var fields, fieldsArr;
fields = document.querySelectorAll(DOMstrings.inputDescription
+ ', ' + DOMstrings.inputValue);
fieldsArr = Array.prototype.slice.call(fields);
fieldsArr.forEach(function(current, index, array){
current.value = "";
});
// this line of code ensures after the users presses enter the
input field goes back to the first.
fieldsArr[0].focus();
},
seeBudget: function(obj) {
document.querySelector(DOMstrings.budgetLabel).textContent =
obj.budget;
document.querySelector(DOMstrings.incomeLabel).textContent =
obj.income;
document.querySelector(DOMstrings.expensesLabel).textContent =
obj.Expense;
document.querySelector(DOMstrings.percentageLabel).textContent
= obj.percentage;
if(obj.percentage >0) {
document.querySelector(DOMstrings.percentageLabel).textContent =
obj.percentage + '%';
} else {
document.querySelector(DOMstrings.percentageLabel).textContent = '--
--';
}
},
//exposing private object so I can pass this to an given module
getDomstrings: function(){
return DOMstrings;
},
};
})();
//Global app controller
var appController = (function(budgetCtrl,UICtrl) {
// function for all event listeners
var eventListeners = function () {
var DOM = UICtrl.getDomstrings();
document.querySelector(DOM.inputBtn).addEventListener('click',
addItem);
document.addEventListener('keypress', function(e) {
if (e.keyCode === 13 || e.which === 13) {
addItem();
}
});
document.querySelector(DOM.container).addEventListener('click',
ctrlDeleteIitem);
};
var budgetUpdate = function(){
//5. calculate the budget
budgetCtrl.calculateBudget();
//6. return the budget
var budget = budgetCtrl.getBudget();
//7. display the budget on the UI
UICtrl.seeBudget(budget);
}
var addItem = function(){
var input, newItem;
//1. get the filed input data
input = UICtrl.getInput();
if (input.description !== "" && !isNaN(input.value) &&
input.value > 0){
//2. add the item to the the budget controller
newItem = budgetCtrl.addItem(input.type,input.description,input.value);
//3. add the item to the UI
UICtrl.addListItems(newItem, input.type)
//4. clear input fields
UICtrl.clearFields();
//5 calculate and update budget
budgetUpdate();
}
};
var ctrlDeleteIitem = function (e) {
var elementID, splitID, type, ID;
elementID =
(e.target.parentNode.parentNode.parentNode.parentNode.id);
<-- problem block of code -->
if(elementID){
splitID = elementID.split('-');
type = splitID[0];
ID = parseInt(splitID[1]);
//1 delete the item from the data structure.
budgetCtrl.deleteItem(type, ID);
//2 delete the item from the UI
<-- end of problem code--->
//3 Update and show the new budget
}
}
return {
init: function() {
console.log('App has started');
UICtrl.seeBudget({budget: 0,
income: 0 ,
Expense:0,
percentage: -1
});
eventListeners();
}
};
})(budgetController, UIController);
// line to run event listener function
appController.init();
expected result is for there not to be an error message and for i.e. if
I was to input test 1 with a value of 12 into my budget app when I click
the button to remove it from my app it should be removed from my data
structure first. thanks in advance.
I am getting a 'NAN' error when I try to map().reduce() from a class method.
All the values are dynamically updated when the form is submitted.
I want to store and add the values of price for each separate Waiter class and store it in the Waiter total.
I am not sure if the problem lies with in the function which is submitting the form or the class method addFood.
I have tried pasrseInt() a few ways but I am not sure of the correct syntax.
/*
//Waiters Section
*/
//Waiter Constructor
class Waiter{
constructor (name){
this.name = name;
this.order = [];
this.total = 0;
}
//function to map() the price argument
//and then reduce() to get the total
addFood (item){
this.order.push(item);
this.total = this.order.map(o => o.price).reduce((a, b) => a + b, 0);
}
};
//Array to store waiters
const waiters = [
new Waiter('Timo'),
new Waiter('Lucian'),
new Waiter('Arpi')
];
const waitersEl = document.getElementById('waiters');
//Adding the waiters to the options menu
waiters.forEach(({name}) => waitersEl.options.add(new Option(name)));
/*
//Food Section Main
*/
//Food Constructor
class Item {
constructor (item, price) {
this.item = item;
this.price = price;
this.label = `${item} (${price})`;
}
}
//Main food array
const mainFood = [
new Item ('Peene Primvera', 14),
new Item("Lasagne", 14),
new Item("Fillet Steak", 20)
];
const foodMain = document.getElementById('menuMain');
//Addin the options for each food and price item inside the dropdown menu
mainFood.forEach(({label, item }) => foodMain.options.add(new Option(label, label)));
/*
//Fucntion for when the form is submited it adds the
*/
const formEl = document.getElementById('mainForm');
formEl.onsubmit = function (e){
//Selecting the choosen index from the user food and which waiter orderd //it which waiter
const foodItem = foodMain.options[foodMain.selectedIndex].value;
const waiterName = waitersEl.options[waitersEl.selectedIndex].value;
const waiter = waiters.find(({ name }) => name === waiterName);
//Logic to check when submited if both feilds are true proceed
if (waiter && foodItem) {
//Calling the function addFood from the Waiter
//class to push the selection to the orders array
//and then reduce it and put the total in the total argument
waiter.addFood(foodItem);
console.log(waiters);
};
return false; // prevents redirect/refresh
};
<form id="mainForm" action="#">
<select id="menuMain" name="foodOrder">
</select>
<select id="waiters" name="waiterSelection">
</select>
<input type="submit" value="Submit">
</form>
This is what I get now after I submit notice the total: NAN:
0: Waiter
addFood: ƒ (item)
name: "Timo"
order: ["Peene Primvera (14.5)", "Peene Primvera (14.5)"]
total: NaN
My desired result would be:
0: Waiter
addFood: ƒ (item)
name: "Timo"
order: ["Peene Primvera (14.5)", "Peene Primvera (14.5)"]
total: 29
Instead of setting the <option>s values to the Item's label set it to the Item's index in the mainFood array, this way it will be easy to get the Item object associated to the selected <option>.
Here is an example:
mainFood.forEach(({label, item }, index) => foodMain.options.add(new Option(label, index)));
And then:
const foodItemIndex = foodMain.options[foodMain.selectedIndex].value;
const foodItem = mainFood[foodItemIndex];
Here is a working version:
class Waiter {
constructor(name) {
this.name = name;
this.order = [];
this.total = 0;
}
addFood(item) {
this.order.push(item);
this.total = this.order.map(o => o.price).reduce((a, b) => a + b, 0);
}
};
const waiters = [
new Waiter('Timo'),
new Waiter('Lucian'),
new Waiter('Arpi')
];
const waitersEl = document.getElementById('waiters');
waiters.forEach(({
name
}) => waitersEl.options.add(new Option(name)));
class Item {
constructor(item, price) {
this.item = item;
this.price = price;
this.label = `${item} (${price})`;
}
}
const mainFood = [
new Item('Peene Primvera', 14),
new Item("Lasagne", 14),
new Item("Fillet Steak", 20)
];
const foodMain = document.getElementById('menuMain');
mainFood.forEach(({
label,
item
}, index) => foodMain.options.add(new Option(label, index)));
const formEl = document.getElementById('mainForm');
formEl.onsubmit = function(e) {
const foodItemIndex = foodMain.options[foodMain.selectedIndex].value;
const foodItem = mainFood[foodItemIndex];
const waiterName = waitersEl.options[waitersEl.selectedIndex].value;
const waiter = waiters.find(({
name
}) => name === waiterName);
if (waiter && foodItem) {
waiter.addFood(foodItem);
console.log(waiters);
};
return false; // prevents redirect/refresh
};
<form id="mainForm" action="#">
<select id="menuMain" name="foodOrder">
</select>
<select id="waiters" name="waiterSelection">
</select>
<input type="submit" value="Submit">
</form>
Without more information, it appears as if some of the data inside this.order is not a number. ParseInt() will return NaN if a value is non-numerical.
If the data in here may possibly contain non-numerical data, you can default that index to 0 by using the double tilde operator ~~ (Math.floor()) which will return 0 in the cases where parseInt() will return NaN.
This will fix the error, but depending on your needs, it may just be ignoring the problem. If this data is not intended to be in that array, I would advise investigating how it gets set there.
let total = [{
price: 3
}, {
price: '5'
}, {
price: 'asdf'
}].map(o => ~~o.price)
.reduce((a, b) => a + b, 0);
console.log(total);
I need to be able to add a student and a grade. however, I am having a difficult time figuring out how to enter a grade. This is what I have so far. When I run the program like this I get: [ Student { name: 'Bob', grades: [], totalGrades: 0 } ] Any help would be appreciated!
The commented out section was an attempt at adding grades, however, I did not work at all.
function Student(name){
this.name = name;
this.grades = [];
this.totalGrades = function(){
this.totalGrades = 0;
this.grades.forEach(grade => {
this.totalGrade += grade;
})
}
}
function Students(){
this.students = [];
// this.grades = [];
/* this.addGrade = function(grade){
this.grades.push(grade);
}*/
this.addStudent = function(student){
this.students.push(student);
}
this.calcTotalGrades = function(){
this.students.forEach(student => {
student.totalGrades();
})
}
}
let students = new Students();
students.addStudent(new Student('Bob'));
students.calcTotalGrades();
console.log(students.students);
Try this function, as a method of your Students:
this.addGrade = function(student,grade) {
this.students.forEach(student => {
if(student.name === student)
student.grades.push(grade)
}
}
To add a new grade:
students.addGrade('Bob',10);
I have an array of objects. Every object in the array has an id and an item property that is an array containing other object. I need to be able to find an element in an array by id. Here is a sample of what I have done so far, but the recursive function is always returning undefined.
How can I quit the function and return the item when I have called the function recursively several times?
$(function () {
var treeDataSource = [{
id: 1,
Name: "Test1",
items: [{
id: 2,
Name: "Test2",
items: [{
id: 3,
Name: "Test3"
}]
}]
}];
var getSubMenuItem = function (subMenuItems, id) {
if (subMenuItems && subMenuItems.length > 0) {
for (var i = 0; i < subMenuItems.length; i++) {
var item;
if (subMenuItems[i].Id == id) {
item = subMenuItems[i];
return item;
};
getSubMenuItem(subMenuItems[i].items, id);
};
};
};
var searchedItem = getSubMenuItem(treeDataSource, 3);
alert(searchedItem.id);
});
jsFiddle
You should replace
getSubMenuItem(subMenuItems[i].items, id);
with
var found = getSubMenuItem(subMenuItems[i].items, id);
if (found) return found;
in order to return the element when it is found.
And be careful with the name of the properties, javascript is case sensitive, so you must also replace
if (subMenuItems[i].Id == id) {
with
if (subMenuItems[i].id == id) {
Demonstration
Final (cleaned) code :
var getSubMenuItem = function (subMenuItems, id) {
if (subMenuItems) {
for (var i = 0; i < subMenuItems.length; i++) {
if (subMenuItems[i].id == id) {
return subMenuItems[i];
}
var found = getSubMenuItem(subMenuItems[i].items, id);
if (found) return found;
}
}
};
I know its late but here is a more generic approach
Array.prototype.findRecursive = function(predicate, childrenPropertyName){
if(!childrenPropertyName){
throw "findRecursive requires parameter `childrenPropertyName`";
}
let array = [];
array = this;
let initialFind = array.find(predicate);
let elementsWithChildren = array.filter(x=>x[childrenPropertyName]);
if(initialFind){
return initialFind;
}else if(elementsWithChildren.length){
let childElements = [];
elementsWithChildren.forEach(x=>{
childElements.push(...x[childrenPropertyName]);
});
return childElements.findRecursive(predicate, childrenPropertyName);
}else{
return undefined;
}
}
to use it:
var array = [<lets say an array of students who has their own students>];
var joe = array.findRecursive(x=>x.Name=="Joe", "students");
and if you want filter instead of find
Array.prototype.filterRecursive = function(predicate, childProperty){
let filterResults = [];
let filterAndPushResults = (arrayToFilter)=>{
let elementsWithChildren = arrayToFilter.filter(x=>x[childProperty]);
let filtered = arrayToFilter.filter(predicate);
filterResults.push(...filtered);
if(elementsWithChildren.length){
let childElements = [];
elementsWithChildren.forEach(x=>{
childElements.push(...x[childProperty]);
});
filterAndPushResults(childElements);
}
};
filterAndPushResults(this);
return filterResults;
}