I have a function that I have modified from some other code, and I am confused. With the 'else if' it seems that the 'Income' object only returns three attributes, rather than the four I need (I can return the value parameter, or I can use the value parameter in a calculation to a different value, but I can't capture both).
return {
addItem: function(type, des, val, price){
var newItem, ID;
if(data.allItems[type].length > 0){
ID = data.allItems[type][data.allItems[type].length - 1].id + 1;
}else{
ID = 0;
}
if (type === 'exp'){
newItem = new Expense(ID, des, val);
}else if (type === 'inc'){
var ben = val * price;
newItem = new Income(ID, des, val, ben);
}
data.allItems[type].push(newItem);
return newItem;
},
I think my problem lies with this function, but as I say, I am now very confused. Is there an obvious problem with it?
Edit: this is the Income function constructor:
var Income = function(id, description, value, price){
this.id = id;
this.description = description;
this.value = value;
this.price = price;
this.ben = ben;
};
If you want to track ben, you can add it to the constructor args.
var Income = function(id, description, value, price, ben){
And add price when you instantiate a new Income object.
newItem = new Income(ID, des, val, price, ben);
Related
Here's the code, set() will not work as I will like to add more names and values because when I want to delete from the program I won't know the autogenerated id. Is there any alternative push() method that will not generate this ID?
//Firebase
var database = firebase.database();
var ref_income = database.ref('Income');
var ref_expense = database.ref('Expense');
//Add month tracker for firebase
var now = new Date();
var months = ["January","February","March","April","May","June","July","August","September","October","November","December"];
var month = now.getMonth();
var ref_budget = database.ref('Budget/' + months[month]);
//To eliminate income or expense
return {
addItem: function(type, des, val){
var newItem,
ID;
// Create new ID
if(data.allItems[type].length > 0){
ID = data.allItems[type][data.allItems[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);
//Identifying using indexes to determine the parameters of the object
var key_des = Object.keys(newItem)[1];
var key_val = Object.keys(newItem)[2];
//Object including descritption as name and income as value to be pushed to firebase
var Expense_data = {
[newItem[key_des]]: newItem[key_val]
}
//Checking on console whether Firebase has recieved it
console.log(Expense_data)
//Adding the objects into firebase
ref_expense.push(Expense_data)
}
else if(type === "inc") {
newItem = new Income(ID,des,val);
var key_des = Object.keys(newItem)[1];
var key_val = Object.keys(newItem)[2]
//Object including descritption as name and income as value to be pushed to firebase
var Income_data = {
[newItem[key_des]]: newItem[key_val]
}
//Checking on console whether Firebase has recieved it
console.log(Income_data);
//Adding the objects into firebase
ref_income.push(Income_data)
}
// Push it into our data structure (Not for firebase)
data.allItems[type].push(newItem);
// Return the new element
return newItem;
},
deleteItem: function(type,id,des){
var ids,
index;
ids = data.allItems[type].map(function(el){
return el.id;
});
index = ids.indexOf(id);
if(index !== -1){
data.allItems[type].splice(index, 1);
}
},
And this is what firebase shows, I won't be able to know the id -M2CsPaog...:
unexpected token: identifier
i've changed the name of the constructor but nothing happens
// this is my javascript code
var budgetController = (function() {
var Expense = function(id, description, value) { //Constructor for the EXPENSE which starts from Capital letter
this.id = id;
this.description = description;
this.value = value;
};
unexpected token: identifier
You're not closing it ()
var budgetController = (function() {
var Expense = function(id, description, value) { //Constructor for the EXPENSE which starts from Capital letter
this.id = id;
this.description = description;
this.value = value;
})(); //Here's the problem
I am following a tutorial to build a budget calculation using modules.For one of the function calcTotal in the module budgetController the guy uses the forEach method and I would like to rewrite it as a for loop.
In this function I am trying to calculate the total of all the expenses and income that the user input on the website. The value get passed to the data.object in the budgetController module. I insert different comments in the full code below to make it as easy as possible to understand.
calcTotal = function(type){
var sum = 0;
data.allItems[type].forEach(function(cur){
sum += cur.value;});
data.totals[type] = sum;
}
var data = {
allItems: {
exp: [],
inc: []
},
totals : {
exp: 0,
inc: 0
},
budget: 0,
percentage: -1
};
The code above is working fine but I tried to do the same with for loop and for some reason is not working.
Could anyone rewrite the forEach method in the function calcTotal as a for loop so I can see what I am doing wrong?
here is the full code:
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;
};
calcTotal = function(type){
var sum = 0;
data.allItems[type].forEach(function(cur){
sum += cur.value;});
data.totals[type] = sum;
}
var data = {
allItems: {
exp: [],
inc: []
},
totals : {
exp: 0,
inc: 0
},
budget: 0,
percentage: -1
};
return{
addItem: function(type, des, val){
var newItem
var ID = 0;
if(data.allItems[type].length > 0 ){
ID = data.allItems[type][data.allItems[type].length - 1].id +1;
}
else{ID = 0};
//create new item based on exp or inc type
if (type === "exp"){
newItem = new Expense(ID, des, val)
}
else if(type === "inc"){
newItem = new Income(ID, des, val);
}
//Push it into our data structure
data.allItems[type].push(newItem);
//returning the new element
return newItem;
},
calculateBudget: function(){
//calculate total income and expenses
calcTotal("exp");
calcTotal("inc");
// calculate the totalBudget
data.budget = data.totals.inc - data.totals.exp;
// calculate the pecentage;
data.percentage = Math.round((data.totals.exp / data.totals.inc) * 100);
},
testing: function(){
console.log(data);
},
getBudget: function(){
return{
budget: data.budget,
expenses: data.totals.exp,
income: data.totals.inc,
percentage: data.percentege
}
}
}
})()
var UIcontroller = (function(){
getDOM = {
inputValue: ".add__value",
inputDescription: ".add__description",
inputType: ".add__type",
addButton: ".add__btn",
expensesList: ".expenses__list",
incomeList: ".income__list"
};
return {
getInput: function(){
return{
value: parseFloat(document.querySelector(getDOM.inputValue).value),
description: document.querySelector(getDOM.inputDescription).value,
type: document.querySelector(getDOM.inputType).value,
};
},
getDomStrings: function(){
return getDOM;
},
displayListItem: function(type, obj){
var html, newHtml, element
if(type === "exp"){
element = getDOM.expensesList;
html = '<div class="item clearfix" id="expense-%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>';
}
else if(type === "inc"){
element = getDOM.incomeList;
html = '<div class="item clearfix" id="expense%id%"><div class="item__description">%description%</div><div class="right clearfix"><div class="item__value">%value%</div><div class="item__percentage">10%</div><div class="item__delete"><button class="item__delete--btn"><i class="ion-ios-close-outline"></i></button></div></div></div>';
}
newHtml = html.replace("%id%", obj.id);
newHtml = newHtml.replace("%description%", obj.description);
newHtml = newHtml.replace("%value%", obj.value)
document.querySelector(element).insertAdjacentHTML("beforeend", newHtml);
},
clearFields :function(){
var fields, arrayField
fields = document.querySelectorAll(getDOM.inputValue +"," + getDOM.inputDescription);
arrayField = Array.prototype.slice.call(fields);
fields.forEach(function(current, index, array){
current.value = "";
});
arrayField[0].focus();
}
}
})()
var controller = (function(budgetCntrl, cntrlUI){
var updateBudget = function(){
var budget
// Calculate the Budget
var calcBudget = budgetCntrl.calculateBudget();
// Return the Budget
budget = budgetCntrl.getBudget();
console.log(budget);
//Display the Budget in UI
}
var addItem = function(){
var input, newItem, addItems, clearFields
// Get the file input data
input = cntrlUI.getInput();
// add new Item to the budget Controller
newItem;
if(input.description !=="" && !isNaN(input.value) && input.value > 0){
newItem = budgetCntrl.addItem(input.type, input.description, input.value);
// display Items in the user interface
addItems = cntrlUI.displayListItem(input.type, newItem);
// clear Fields
clearFields = cntrlUI.clearFields();
updateBudget();
// calculate the budget
// display Budget in the user interface
}
}
var setupEventListener = function(){
var DOM = cntrlUI.getDomStrings();
document.querySelector(DOM.addButton).addEventListener("click", addItem);
}
return{
init: function(){
console.log("app has started");
setupEventListener();
}
}
})(budgetController, UIcontroller)
controller.init();
I hope I was clear.
This code:
calcTotal = function(type){
var sum = 0;
data.allItems[type].forEach(function(cur){
sum += cur.value;});
data.totals[type] = sum;
}
Could be re-written as:
function calcTotal(type){
var sum = 0;
for (let i = 0; i < data.allItems[type].length; i++) {
sum += data.allItems[type][i].value;
}
data.totals[type] = sum;
}
Full source: https://jsfiddle.net/gpj40raf/2/
However, may I give you some code review advice?
calcTotal depends on data defined in the enclosing environment. This is not a good idea. It will be better to pass data as a parameter (in certain cases using the closure is good, but this is not one of them). One of the bugs that you have in the complete code is that calcTotal depends on values defined bellow. This will work because of JavaScript hoisting, but is not a good practice.
Note that the forEach code depends that each value is in a value property, but the rest of the code is assuming that values are numbers (i.e. calculateBudget).
The calculation of the total could be abstracted easily without depending on a particular data "shape". For example: data.totals['type']=calcTotal(data.allItems['type']). This makes easy to understand what's going on.
Take a look to Array functions map/reduce/filter. What they do is to abstract certain patterns in a way that's more declarative. For example, to sum values you can use: values.reduce((total, value)=>total+value, 0) (in one line you can express the same as calcTotal).
Take a look to the ES6 constructs. All the new browsers support that today, and you'll be able to use const/let, string literals ,and class for Expense and Income.... the code will be shorter and easy to read.
Can somebody help me with this, i m new to javaScript and i m stuck at this point.I made an output of certain object within my array ,that output is writing a persons values, within that object(Osoba) there is an array of his friends and all values inside are IDs of each person, http://prntscr.com/i9m2ti how can i make that ID of a friend array ( within the object ) to be a first name and surname of that person which id is in array and when i want to output a certain object so there will be friends[ their names instead of IDs], can someone write me down how can i do that. Thanks for understanding.
class Osoba{
constructor(id,firstName,surname,age,gender,friends){
this._id = id ;
this._firstName = firstName;
this._surname = surname;
this._age = age;
this._gender = gender;
this._friends = friends;
}
get id() {
return this._id;
}
set id(id){
this._id = id;
}
get firstName() {
return this._firstName;
}
set firstName(firstName){
this._firstName = firstName;
}
get surname() {
return this._surname;
}
set surname(surname){
this._surname = surname;
}
get age() {
return this._age;
}
set age(age){
this._age = age;
}
get gender() {
return this._gender;
}
set gender(gender){
this._gender = gender;
}
get friends() {
return this._friends;
}
set friends(friends){
this._friends = friends;
}
}
var osobe = []; // my array
$(function() {
$.getJSON('https://raw.githubusercontent.com/Steffzz/damnz/master/
data.json' , function(data)
{
var json = jQuery.parseJSON(JSON.stringify(data));
for(person of json)
{
var id = person['id'] ;
var firstName = person['firstName'] ;
var surname = person['surname'] ;
var age = person['age'] ;
var gender= person['gender'] ;
var friends = person['friends'] ;
var x = new Osoba(id,firstName,surname,age,gender,friends);
osobe.push(x); //filling array with objects and their values
}
console.log(osobe);
document.write(JSON.stringify(osobe[0])) //output of a certain object
})
});
Assuming json is an array and contains all people you can map over friends array and find the person with that id: person['friends'].map( and json.find(function(person){person.id===friendId});.
Then return an object containing that person's first and last name:
console.log("json is:",JSON.stringify(json,undefined,3));
var friends = person['friends'].map(
function(friendId){
console.log("friendID is:",friendId);
var friend = json.find(function(person){return person.id===friendId;});
console.log("friend is:",JSON.stringify(friend,undefined,2));
return {
firstName:friend.firstName,
surname:friend.surname
}
}
);
Now if that "does not work" could you please specify the output of the logs, any errors and expected results versus actual results?
UPDATE FULL CODE
Since the json is all your data you can pass that into your Osoba constructor. The friends getter will use the data to create an array Osaba items that will have data and friends that will create an array of Osaba ...
class Osoba {
constructor(id, firstName, surname, age, gender, friends, data) {//added data
this._id = id;
this._firstName = firstName;
this._surname = surname;
this._age = age;
this._gender = gender;
this._friends = friends;
this._data = data;//data has all the people
}
get id() {
return this._id;
}
set id(id) {
this._id = id;
}
get firstName() {
return this._firstName;
}
set firstName(firstName) {
this._firstName = firstName;
}
get surname() {
return this._surname;
}
set surname(surname) {
this._surname = surname;
}
get age() {
return this._age;
}
set age(age) {
this._age = age;
}
get gender() {
return this._gender;
}
set gender(gender) {
this._gender = gender;
}
//modified friends getter returning an array of Osoba items
get friends() {
var me = this;
return this._friends.map(
function (friendId) {
var friend = me._data.find(function (person) { return person.id === friendId; });
return new Osoba(
friend.id,
friend.firstName,
friend.surname,
friend.age,
friend.gender,
friend.friends,
me._data
);
}
);
}
set friends(friends) {
this._friends = friends;
}
}
$.getJSON('https://raw.githubusercontent.com/Steffzz/damnz/master/data.json')
.then(
json => {
var people = json.map(
person =>
new Osoba(
person.id,
person.firstName,
person.surname,
person.age,
person.gender,
person.friends,
json
)
);
//you can keep getting friends now, because Osoba is
// creating new Osoba objects based on id's and data you pass in
console.log(people[0].friends[0].friends[0].friends[0]);
}
);
instead of
var friends = person['friends'] ;
try
var friends = [];
var friendIDs = person['friends'] ; //retrieve friendIDs
for(friendID of friendIDs) { //loop over friendIDs
var friend = json[friendID]; //get friend dataset out of the json
friends.push(friend['firstName']); // add friend dataset to friends array
}
I assume here that those friends are in that json aswell. and that the ids represent that index inside that array. if the indexes aren't those ids this won't work. feel free to comment if thats the case and i'll edit my answer.
If i understand correctly you just want to use id for id, firstname, and lastname. so just pass id 3 times instead of firstname and lastname:
var x = new Osoba(id,id,id,age,gender,friends);
~~~~
Ok so what you want is actually that the id property within each friend object be the first and last name of the friend instead of an idea code. So it's basically just the opposite of what i suggested earlier. All you have to do is manipulate what you push to id. There's no obligation on it being the id from the json.
so in your case:
for(person of json){
var id = person['firstName'] + "" + person['surname']; // line to change.
var firstName = person['firstName'] ;
var surname = person['surname'] ;
var age = person['age'] ;
var gender= person['gender'] ;
var friends = person['friends'] ;
var x = new Osoba(id,firstName,surname,age,gender,friends);
osobe.push(x); //filling array with objects and their values
}
Converting function list into order so it is OOP.
Currently I've a class shoppingCart functionality.
Inside shoppingCart we have; save, load, remove, etc and than access it.
a) Is this written in OOP correctly
b) How do you access specific functions.
JS
var cart = [];
function shoppingCart() {
//var Item = function(title, description, price, image_url, count) {
this.newitem = function(title, description, price, image_url, count) {
this.title = title
this.description = description
this.price = price
this.image_url = image_url
this.count = count
}
//function addIteamToCart(title, description, price,image_url, count){
this.addNewitem = function addIteamToCart(title, description, price, image_url, count) {
for (var i in cart) {
console.log(cart);
if (cart[i].title === title) {
cart[i].count += count;
return;
}
}
var item = new Item(title, description, price, image_url, count);
console.log(item);
cart.push(item);
saveCart();
}
};
console.log(shoppingCart.newitem(sss,ddd,zzz,sss));
You need to create a ShoppingCart object:
var sc = new shoppingCart();
sc.newitem(sss, ddd, zzz, sss);
console.log(sc);
BTW, the cart variable should probably be local to the shoppingCart function, not a global variable. And then it should be passed as an argument to saveCart().