javascript adding into arrays - javascript

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);

Related

Function to count lists of objects

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 }
}
}

object value is only increasing in the first element of the array

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);

Is using Eval a good idea?

I'd come to a situation where I had to get the object value dynamically from an array having object keys coming from an api. I came to this approach by using eval.
class App extends React.Component {
constructor() {
super();
this.state = {
title: 'Developers',
descp: 'They are just amazing! JK',
names: ['title', 'descp']
}
}
getVal(objKey) {
let { title, descp } = this.state;
return eval(objKey);
}
render() {
let {names} = this.state;
return (
<div>
<h2>{this.getVal(names[0])}</h2>
<div>{this.getVal(names[1])}</div>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
The above code works correctly.
Another approach I found later:
render() {
let {names} = this.state;
return (
<div>
<h2>{this.state[names[0]]}</h2>
<div>{this.state[names[1]]}</div>
</div>
)
}
Outputs the same result. But my question is that if I use eval with the following case, is it a good approach to do so?
Eval should be avoided as it can be very dangerous. You can safely replace your eval call with accessing property via bracket notation.
getVal(objKey) {
if(this.state.hasOwnProperty(objKey)){
return this.state[objKey];
} else {
// handle missing property
}
}
Eval is generally avoided as it allows the client to insert and evaluate their own expressions in your code.
That being said, JavaScript being a client side language already allows full access to the user, so there isn't really a good reason not to use it.
As long as the user can only mess with their own session, i wouldn't worry. Security should be handled server side anyway so: Beware but don't simply ignore Eval.
EDIT 1 - Defending Eval
The comments pointed out some issues, mainly Performance/Optimization impact, which this answer explains in depth. Basically, since it's Just-In-Time compiling anyway, you don't really lose that much in terms of performance.
As for an example on a use case, here is a template example i whipped up, which also uses the controversial with statement:
var Template = /** #class */ (function () {
function Template(html) {
this.html = html;
}
Template.prototype.apply = function (params, returnDOMObject) {
if (params === void 0) { params = {}; }
if (returnDOMObject === void 0) { returnDOMObject = false; }
with (params) {
var html = eval('`' + this.html.replace(Template.regexes.encapsulated, function (n) {
return n
.replace(Template.regexes.start, '${')
.replace(Template.regexes.end, '}');
}) + '`');
}
if (returnDOMObject) {
return document.createRange().createContextualFragment(html);
}
return html;
};
Template.regexes = {
encapsulated: new RegExp('{{.*?}}', 'igm'),
start: new RegExp('\{{2,}', 'igm'),
end: new RegExp('\}{2,}', 'igm')
};
return Template;
}());
//TEST
var persons = [
{ name: "Peter", age: 25 },
{ name: "Ole", age: 55 },
];
var templates = [];
var container = document.body.appendChild(document.createElement("div"));
var leftBox = container.appendChild(document.createElement("div"));
var rightBox = container.appendChild(document.createElement("div"));
leftBox.style.width = rightBox.style.width = "50%";
leftBox.style.height = rightBox.style.height = "500px";
leftBox.style.cssFloat = rightBox.style.cssFloat = "left";
var leftList = leftBox.appendChild(document.createElement("select"));
leftBox.appendChild(document.createElement("br"));
var leftText = leftBox.appendChild(document.createElement("textarea"));
leftText.style.width = "100%";
leftText.style.resize = "vertical";
var rightOutput = rightBox.appendChild(document.createElement("div"));
function updateLists() {
leftList.innerHTML = '';
for (var i = 0; i < templates.length; i++) {
var template = templates[i];
var option = document.createElement("option");
option.value = option.innerHTML = template.name;
leftList.appendChild(option);
}
}
var h1Template = new Template("<h1>{{name}}</h1>");
var h2Template = new Template("<h2>{{age}} is no age!</h2>");
var pTemplate = new Template("<p>{{name}} may be {{age}}, but is still going strong!</p>\n<p>(When he's {{age*2}} though...)</p>");
var personTemplate = new Template("<p>\n{{ h1Template.apply(params) }}\n{{ h2Template.apply(params) }}\n{{ pTemplate.apply(params) }}\n</p>");
templates.push({ name: "personTemplate", template: personTemplate });
templates.push({ name: "h1Template", template: h1Template });
templates.push({ name: "h2Template", template: h2Template });
templates.push({ name: "pTemplate", template: pTemplate });
function updateOutput() {
rightOutput.innerHTML = '';
for (var pi = 0; pi < persons.length; pi++) {
var person = persons[pi];
rightOutput.appendChild(personTemplate.apply(person, true));
}
}
function leftTextChange() {
templates.find(function (val) { return val.name === leftList.value; }).template.html = leftText.value;
updateOutput();
}
function leftListChange() {
leftText.value = templates.find(function (val) { return val.name === leftList.value; }).template.html;
}
updateLists();
leftList.onchange = leftList.onkeyup = leftListChange;
leftText.onchange = leftText.onkeyup = leftTextChange;
leftListChange();
updateOutput();
Here the users input text is being interpreted live, while the user is watching. No security concerns, since it's all client side.

(Very) Novice Javascripter Needing Help Understanding Practical Functions

So I am building an election script that assigns candidates to partys and electorates then assigns them their votes but I am so scrambled so if someone can help me understand what I'm doing, for instance this function here:
class Electorate {
constructor (newNames) {
this.name = newNames
this.allMyElectorates = []
this.addWinner = []
this.addPartyVotes = []
}
addElectorate (...newNames) {
for(let i=0;i<newNames.length;i++){
var newElectorate = new Electorate(newNames[i], this.addWinner,
this.addPartyVotes)
this.allMyElectorates.push(newElectorate)
return newElectorate
}
}
addWinner(...newNames){
theParty = myElection.findParty (partyName)
if (theParty == undefined){
myElection.addIndependant (cadidateName)
}else{
theCandidate = theParty.findCandidate (candidateName)
}if (theCandidate == undefined) {
theParty.addElectorateMP (candidateName, this)
}else{
theCandidate.setElectorate (this)}
}
function totalVotes(...newNumbers){
for(let i=0;i<newNumbers.length;i++){
var newTotalVotes = new totalVotes(newNumbers[i], this)
this.addPartyVotes.push(newTotalVotes)
return newTotalVotes
}
}
function addWinner(...newNames){
for(let i=0;i<newNumbers.length;i++){
var addWinner = new Winner(newNames[i], this)
this.addWinner.push(newWinner)
return addWinner
}
}
}
And this is what I'm trying to reference at the moment:
anElectorate = theElection.addElectorate('Auckland Central')
anElectorate.addWinner('KAYE, Nicola Laura', 'National Party')
anElectorate.addPartyVotes(329, 85, 10, 486, 3, 2, 6242, 553, 6101, 158,
12652, 1459, 7, 17, 53, 99)
I want to create a new function (totalVotes) using data collected from addPartyVotes (in the controller class) that has to to be called from other classes, it has it's variables and I'm pushing it out in an array then returning it so what am I doing wrong?
I've tried asking people in my class and the tutors but I feel like they just fob me off without giving me any real guidance, I'm an engineer not a programmer so this is very difficult to wrap my head around.
There is no single line or point of code which is breaking your program.
There are countless errors, and will simply not function.
Take a look at this example (JS ES5):
var Electorate = {
candidates: [],
init: function() {
this.candidates = [];
return this;
},
getCandidateByName: function(name) {
var filter_candidate_by_name = this.candidates.filter(function(d) {
return d.name === name;
})[0];
var index_of_candidate = this.candidates.indexOf(filter_candidate_by_name);
return this.candidates[index_of_candidate];
},
calculateWinner: function() {
var max_votes = Math.max.apply(Math, this.candidates.map(function(d) {
return d.votes.length;
}));
if (!max_votes || isNaN(max_votes)) return false;
var records_with_max_votes = this.candidates.filter(function(d) {
return d.votes.length === max_votes;
});
var result = {};
if (records_with_max_votes.length > 1) {
result.result = 'Tied';
result.candidates = records_with_max_votes;
var list_of_candidate_names = records_with_max_votes.map(function(d) {
return d.name;
}).join(', ');
result.explaination = 'Tied between ' + list_of_candidate_names + ', with a count of ' + max_votes + ' votes each';
} else if (records_with_max_votes.length === 1) {
result.result = 'Won';
result.candidate = records_with_max_votes[0];
result.explaination = records_with_max_votes[0].name + ' won with a count of ' + max_votes + ' votes';
}
return result;
}
};
var Voter = {
name: null,
age: null,
gender: null,
init: function(name, age, gender) {
if (!name || !age || !gender) return false;
this.name = name;
this.age = age;
this.gender = gender;
return this;
}
};
var Candidate = {
name: null,
votes: [],
init: function(name) {
this.name = name;
this.votes = [];
return this;
},
castVote: function(voter) {
this.votes.push(voter);
return this;
}
};
var electorate = Object.create(Electorate).init();
electorate.candidates.push(
Object.create(Candidate).init('Mr. John Smith'),
Object.create(Candidate).init('Mr. Adam John'),
Object.create(Candidate).init('Ms. Christina Brown')
);
electorate
.getCandidateByName('Mr. John Smith')
.castVote(Object.create(Voter).init('Maria Smith', 38, 'Female'))
.castVote(Object.create(Voter).init('John Doe', 118, 'Male'))
.castVote(Object.create(Voter).init('John Doe', 44, 'Male'));
electorate
.getCandidateByName('Ms. Christina Brown')
.castVote(Object.create(Voter).init('John Doe', 235, 'Male'))
.castVote(Object.create(Voter).init('John Doe', 34, 'Male'))
.castVote(Object.create(Voter).init('John Doe', 22, 'Male'));
console.log(electorate.calculateWinner());
You can see that it collects information and takes into account Candidates and Voters which can be created and added to the appropriate data location in the Electorate.
It can then go ahead after all votes are cast, and announce the selected winner or the tied winners.
My advice is to brush up on your Javascript knowledge, and try not using ES6 additions.
This is a great resource to brush up on Javascript (for all levels of experience): https://github.com/getify/You-Dont-Know-JS
Functions cannot take this as an argument.
A valid function would look like this:
function totalVotes ( vote ) {
return "something";
}
If you can share your entire script pertaining to the voting/election program, I could help guide you and your approach to writing effective code.

Find an element in an array recursively

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;
}

Categories