making an array of custom objects with default values in JavaScript - javascript

So what I'm trying to do is an array of custom objects. So I have a constructor, but I don't pass values through parameters, rather I want to initialise all to 0 and the use getters or setters to retrieve them. Obviously, it doesn't work but I don't know why. Everywhere I looked the object were created by passing values through parameters, so I just guessed.
My constructor
function Stol()
{
var cipsy = 0, kofca = 0, dzus = 0, sypcaj = 0, vrecaj = 0, coko = 0,jedlo = 0, pernik = 0, kava = 0, ucet = 0;
this.cipsy = cipsy;
this.kofca = kofca;
this.dzus = dzus;
this.sypcaj = sypcaj;
this.vrecaj = vrecaj;
this.coko = coko;
this.jedlo = jedlo;
this.pernik = pernik;
this.kava = kava;
this.ucet = ucet;
this.reset = reset;
function reset() {
this.cipsy = 0;
this.kofca = 0;
this.dzus = 0;
this.sypcaj = 0;
this.vrecaj = 0;
this.coko = 0;
this.jedlo = 0;
this.pernik = 0;
this.kava = 0;
Obrat += this.ucet;
this.ucet = 0;
}
this.addItem = addItem;
function addItem(type, number) {
switch (type) {
case 0 : this.cipsy += number; break;
case 1 : this.kofca += number; break;
case 2 : this.dzus += number; break;
case 3 : this.sypcaj += number; break;
case 4 : this.vrecaj += number; break;
case 5 : this.coko += number; break;
case 6 : this.jedlo += number; break;
case 7 : this.pernik += number; break;
case 8 : this.kava += number; break;
}
}
this.getItem = getItem;
function getItem(type) {
var item;
switch (type) {
case 0 : item = this.cipsy; break;
case 1 : item = this.kofca; break;
case 2 : item = this.dzus; break;
case 3 : item = this.sypcaj; break;
case 4 : item = this.vrecaj; break;
case 5 : item = this.coko; break;
case 6 : item = this.jedlo; break;
case 7 : item = this.pernik; break;
case 8 : item = this.kava; break;
}
return item;
}
}
then here I create the Array
var stol = new Array();
for (var i = 0; i < 14; i++) {
stol[i] = new Stol();
}
and eventually I want to modify some spans using jQuery like this. #selecStol is a dropdown list (the switch is not completed).
$("#selecStol").change(function(){
var myStol = stol[$(this).find(":selected").val()];
for (i = 0; i < 14; i++) {
switch (i) {
case 0 : $("#cipsy").text(myStol.getItem(i));break;
}
}
})
But it doesn't work, and I don't know which part.

That is because this in your getter function isn't what you think.
If you check the this in a dev tool, you'll probly see the window object. To solve that, you can either save the this in a var like that :
function Stol(){
var self = this;
//All your variable "this"
this.getItem = function(type){
//In this function you use self instead of this
//ex : case 0 : item = self.cipsy; break;
}
}
Or the recommanded way, using prototype :
function Stol(){
//Your things
}
Stol.prototype.getItem = function(type){
//Now "this" will be Stol object.
}
Note that i've only used getItem function for the answer, but all your others function have the same problem.

Related

TypeError in Javascript

function url_info()
{
var url_val=document.getElementsByClassName("spc-tab");
var current_s=0;
for(var i=0;i<url_val.length;i++)
{
var url_class=url_val[i].className.split(" ");
if(url_class[1]!=null)
{
if(url_class[1]=="selected")
{
current_s=i;
break;
}
}
}
var temp_1=url_val[current_s].text; //**Error here**
return(temp_1);
}
In this function url_info i am getting the TypeError But i don't know why?? .... as My var current_s is defined within the scope and integer...
why write this much of code when one line can do:
function url_info() {
var temp_1 = "";
var url_val = document.querySelector(".spc-tab.selected");
temp_1 = url_val[0].text > 0 ? url_val[0].text : temp_1;
return (temp_1);
}
and second, you don't require to convert your class name to string then split. You just can access them through classlist. Then use contains.
function url_info() {
var url_val = document.getElementsByClassName("spc-tab");
var current_s = 0;
for (var i = 0; i < url_val.length; i++) {
var isSelected = url_val[i].classList.contains("selected");
if (isSelected) {
current_s = i;
break;
}
}
var temp_1 = url_val[current_s].text;
return (temp_1);
}

JavaScript mocked function returning undefined in tests

I'm trying to test some JavaScript functions that are part of a larger React app. They make heavy use of the module pattern, which I suspect may be what I'm not understanding correctly. Here is the script I'm testing (nearly identical to the one actually used in the real app except that GetFeedData.getFeedData in the real one makes a call to an external API):
const GetFeedData = (function () {
let feed, feedId;
return {
getFeedId: function (sub) {
switch (sub) {
case '1': case '2': case '3': case '4': case '5': case '6': case 'S':
feedId = 1;
break;
case 'A': case 'C': case 'E':
feedId = 26;
break;
case 'N': case 'Q': case 'R': case 'W':
feedId = 16;
break;
case 'B': case 'D': case 'F': case 'M':
feedId = 21;
break;
case 'L':
feedId = 2;
break;
case 'G':
feedId = 31;
break;
}
},
getFeedData: function () {
if (feedId === 2) {
feed = require('./MockData');
}
},
feed: feed
};
})();
const ReverseStop = (function () {
let stopIdN, stopIdS;
const stopData = require('../utils/stops');
return {
reverseStop: function (sub, stop) {
var invalidEntries = 0;
function filterByName (item) {
if (item.stop_name == stop && typeof item.stop_id === 'string' && item.stop_id.charAt(0) == sub) {
return true;
}
invalidEntries ++;
return false;
}
var stopObjs = stopData.filter(filterByName);
for (var i = 0; i < stopObjs.length; i++) {
if (stopObjs[i].stop_id.charAt(stopObjs[i].stop_id.length - 1) == 'N') {
stopIdN = stopObjs[i].stop_id;
} else if (stopObjs[i].stop_id.charAt(stopObjs[i].stop_id.length - 1) == 'S') {
stopIdS = stopObjs[i].stop_id;
}
}
},
stopIdN: stopIdN,
stopIdS: stopIdS
};
})();
export const IsDelayN = (function () {
let noDelay, yesDelay, nextArrival, delay;
return {
isDelay: function (sub, stop) {
GetFeedData.getFeedId(sub);
GetFeedData.getFeedData();
ReverseStop.reverseStop(sub, stop);
var arrivals = [];
var delays = [];
function dataFilter () {
var invalidEntries = 0;
var feedObjs = GetFeedData.feed.filter(function (feedObj) {
if (feedObj.entity.trip_update.stop_time_update.stop_id == ReverseStop.stopIdN) {
return feedObj.entity.trip_update.stop_time_update;
}
});
for (var i = 0; i < feedObjs.length; i++) {
arrivals.push(feedObjs.arrival.time.low);
delays.push(feedObjs.arrival.delay);
}
}
nextArrival = Math.min(...arrivals);
var delayIndex = arrivals.indexOf(nextArrival);
delay = delays.delayIndex;
if (delay === null || Math.ceil(delay / 60) <= 5) {
noDelay = Math.ceil((nextArrival - GetFeedData.feed.header.timestamp.low) / 60);
} else {
yesDelay = Math.ceil(delay / 60);
}
},
noDelay: noDelay,
yesDelay: yesDelay,
nextArrival: nextArrival
};
})();
export const IsDelayS = (function () {
let noDelay, yesDelay, nextArrival, delay;
return {
isDelay: function (sub, stop) {
GetFeedData.getFeedId(sub);
GetFeedData.getFeedData();
ReverseStop.reverseStop(sub, stop);
var arrivals = [];
var delays = [];
function dataFilter () {
var invalidEntries = 0;
var feedObjs = GetFeedData.feed.filter(function (feedObj) {
if (feedObj.entity.trip_update.stop_time_update.stop_id == ReverseStop.stopIdS) {
return feedObj.entity.trip_update.stop_time_update;
}
});
for (var i = 0; i < feedObjs; i++) {
arrivals.push(feedObjs.arrival.time.low);
delays.push(feedObjs.arrival.delay);
}
}
nextArrival = Math.min(...arrivals);
var delayIndex = arrivals.indexOf(nextArrival);
delay = delays.delayIndex;
if (delay === null || Math.ceil(delay / 60) <= 5) {
noDelay = Math.ceil((nextArrival - GetFeedData.feed.header.timestamp.low) / 60);
} else {
yesDelay = Math.ceil(delay / 60);
}
},
noDelay: noDelay,
yesDelay: yesDelay,
nextArrival: nextArrival
};
})();
What I'm attempting to do is separate out my functions so I have several shorter ones I can call in the exported functions, rather than one or two extremely long functions. Because I need to call a couple variables - GetFeedData.feed, ReverseStop.stopIdN, and ReverseStop.stopIdS in the exported functions, I am assuming that the module pattern is a better way to go than using callbacks. I could totally be wrong.
In my tests, I try log noDelay, nextArrival, and delay to the console to see if they are defined. I'm using Jest, if that information is helpful. I'll omit the other parts of my test for now because they don't seem relevant (please correct me if that's wrong), but here is that section:
it('correctly takes input at beginning of api logic and outputs expected values at end', () => {
IsDelayN.isDelay('L', 'Lorimer St');
IsDelayS.isDelay('L', 'Lorimer St');
expect(IsDelayN.noDelay).toBeTruthy();
expect(IsDelayN.yesDelay).toBeFalsy();
expect(IsDelayS.noDelay).toBeTruthy();
expect(IsDelayS.yesDelay).toBeFalsy();
console.log('IsDelayN noDelay: ' + IsDelayN.noDelay);
console.log('IsDelayN nextArrival: ' + IsDelayN.nextArrival);
console.log('IsDelayN delay: ' + IsDelayN.delay);
console.log('IsDelayS noDelay: ' + IsDelayS.noDelay);
console.log('IsDelayS nextArrival: ' + IsDelayS.nextArrival);
console.log('IsDelayS delay: ' + IsDelayS.delay);
});
The tests prior to my console.log()s are all passing, but every console.log() is turning up undefined. Also, the script that's actually being called by my React components is coming up with the same results. I have my component set to render null if these variables aren't defined, and that's exactly what's happening.
Any help with understanding this is greatly appreciated.
You do not set the modules correctly, when setting a member value you should mutate the object, now you just set a variable value.
The following should work for you:
var module = (function(){
const ret = {
mutateSomething:function(value){
//set otherValue on the object returned (mutate ret)
ret.otherValue = value;
}
,otherValue:undefined
};//create the object first
return ret;//then return the object
}())//IIFE
console.log("before mutate:",module.otherValue);
module.mutateSomething("Hello World");
console.log("after mutate:",module.otherValue);

Javascript: Updating direction of robot using string is not working

Javascript
Trying to work on a simple game of moving a robot using key L(to move left), R(to move right), F(to move forward) from a specific position on a board where it is created using 5x5 dimension and always facing North (shown as N). Clicking a Move button after entering any of above string/characters should display the current position.
Expected: For instance if I say board dimension (5x5), current position (3,3), enter 'R' and hit Move button it should show the resulting position as (3,3) E because the robot was facing north (N) first and now asked to move to RIGHT which would be east (E).
Problem: Can't seem to spot the issue in my code why the direction is not getting updated.
Here is the code that does all calculation and update.
var RobotManager = {
roomType: 'square',
roomParameters: [5, 5],
robotDirection: 'N',
robotPosition: [1, 2],
possibleDirections: ["N", "E", "S", "W"],
errorMessageNumber: -1,
errorMessage: [
"error0",
"error1",
"all other errors removed to keep code clean"
],
squares: [],
stringCommandThatExexuted: '',
init: function() {
var regexp_number = /^[1-9]$|([1][0-9])$/;
return true;
},
// This should move the robot to the right direction
turnRight: function() {
var movePosition = this.possibleDirections.indexOf(this.robotDirection);
if (movePosition == this.possibleDirections.length - 1) {
return this.possibleDirections[0];
}
return this.possibleDirections[movePosition + 1];
},
turnLeft: function() {
var movePosition = this.possibleDirections.indexOf(this.robotDirection);
if (movePosition == 0) {
return this.possibleDirections[this.possibleDirections.length - 1];
}
return this.possibleDirections[movePosition - 1];
},
moveForward: function() {
var nextPosition = this.getNextPosition();
var nextSquare = {
X: nextPosition[0],
Y: nextPosition[1]
};
if (this.isSquareAvailable(nextSquare)) {
this.robotPosition = nextPosition;
} else {
this.errorMessageNumber = 1;
return false;
}
return true;
},
//this is not getting executed to update the direction
getNextPosition: function() {
var x, y;
switch (this.robotDirection) {
case "N":
x = this.robotPosition[0];
y = this.robotPosition[1] - 1;
break;
case "E":
x = this.robotPosition[0] + 1;
y = this.robotPosition[1];
break;
case "W":
x = this.robotPosition[0] - 1;
y = this.robotPosition[1];
break;
case "S":
y = this.robotPosition[1] + 1;
x = this.robotPosition[0];
break;
}
return [x, y];
},
//First button clicks comes here and just renders default value of direction
getRobotsPositionAndDirection: function() {
if (this.errorMessageNumber <= 1) {
var message = "";
if (this.errorMessageNumber == 0) {
return this.errorMessage[0];
}
if (this.errorMessageNumber == 1) {
message = this.errorMessage[1];
}
return message + this.robotPosition[0] + " " + this.robotPosition[1] + " " + this.robotDirection;
}
return this.errorMessage[8];
},
checkCommandString: function(string) {
var english_command = /^[LRF]*$/;
if (english_command.test(string)) {
return true;
}
this.errorMessageNumber = 0;
return false;
},
getCommandStringThatExecuted: function() {
return this.stringCommandThatExexuted;
},
//This is where index is passed as 0 and doesn't execute
moveRobotToOnePosition: function(letter) {
switch (letter) {
case 'L':
this.robotDirection = this.turnLeft();
this.stringCommandThatExexuted += 'L';
break;
case 'R':
this.robotDirection = this.turnRight();
this.stringCommandThatExexuted += 'R';
break;
case 'F':
if (this.moveForward()) {
this.stringCommandThatExexuted += 'F';
return true;
} else {
return false;
}
break;
}
},
moveRobot: function(string) {
string = string.toUpperCase();
if (this.checkCommandString(string)) {
var array = string.split('');
for (var i = 0; i < array.length; i++) {
return this.moveRobotToOnePosition(i);
}
return true;
}
this.errorMessageNumber = 0;
}
}
So your problem is actually pretty simple, and my apologies for taking so long to figure this out. The issue is that you were passing the array index and not the array element.
moveRobot: function(string) {
string = string.toUpperCase();
if (this.checkCommandString(string)) {
var array = string.split('');
for (var i = 0; i < array.length; i++) {
// return this.moveRobotToOnePosition(i);
this.moveRobotToOnePosition(array[i]); // don't use return here unless you want to exit the function.
}
return true;
}
this.errorMessageNumber = 0;
}

Switch statement is returning no value

I have a test i'm writing which reads in a string and then takes that string and applies it to a switch statement. I then match the string to the case and set an integer value which I pass back to the spec page which then passes the int value to another test that I use for an if statement. I cannot get the int to pass so the if statement will not work properly.
The object for switch:
var appsNotPurchased = 0;
this.checksHomeSublevel = function(mmCode) {
browser.get('https://iplan-qa.meetingmatrix.com/Home/Index/' + mmCode);
marketingObjects.level.getText().then(function(text) {
var homeText = text;
browser.get('https://iplan-qa.meetingmatrix.com/Home/Apps/' + mmCode);
expect($('div.apps-subscription > span').getText()).toEqual('iPlan Level: ' + homeText);
switch (homeText) {
case 'Select':
console.log(homeText);
appsNotPurchased = 6;
return appsNotPurchased;
break;
case 'Content':
console.log(homeText);
appsNotPurchased = 0 || 1 || 2 || 3 || 4 || 5 || 6;
return appsNotPurchased;
break;
}
});
the testSpec describe function:
describe('should upload media: ', function() {
it('should select add media', function() {
var mmCode = "ACC0572";
var appsNotPurchased = appsObjects.checksHomeSublevel(mmCode);
appsObjects.checksSubLevelSelect(mmCode, appsNotPurchased);
});
});
The object I am passing the value to:
this.checksSubLevelSelect = function(mmCode, appsNotPurchased) {
//counts the apps
apps.count().then(function(count) {
expect(count).toEqual(7);
for (var i = 0; i < count; i++) {
if (appsPlace == appsNotPurchased) {
//does something here
} else {
//does something here
}
appsPlace++;
}
});
};
You should be returning an object instead of || statement. Also return statement should be written outside switch rather than inside it.
Simplest solution would be to use a global variable appsNotPurchased which stores the value and then you can use it in your test specs without returning. But that would be a poor coding standard.
Second solution would be to return a promise of the function as protractor executes asynchronously.
Here's an example of second solution -
this.checksHomeSublevel = function(mmCode) {
var getval = marketingObjects.level.getText().then(function(text) {
switch (homeText) {
case 'Select':
console.log(homeText);
appsNotPurchased = [6];
break;
case 'Content':
console.log(homeText);
appsNotPurchased = [0, 1, 2, 3, 4, 5, 6]; //either use array or object
break;
default:
console.log("Default");
}
return appsNotPurchased;
});
return protractor.promise.fulfilled(getval);
};
and then use it like a promise in your spec -
appsObjects.checksHomeSublevel(mmCode).then(function(appsNotPurchased){
appsObjects.checksSubLevelSelect(mmCode, appsNotPurchased);
});
Use above result in your function now -
this.checksSubLevelSelect = function(mmCode, appsNotPurchased) {
//counts the apps
apps.count().then(function(count) {
expect(count).toEqual(7);
for (var i = 0; i < count; i++) {
if (appsPlace == appsNotPurchased[i]) {
//does something here
} else {
//does something here
}
appsPlace++;
}
});
};
Hope it helps.

if/else statement not registering if

My code seems to log the if statement as false, even though if I console.log the conditions it returns as true. Why is it doing that? (the code , that is not working is indicated by error not bypassing.)
function StaffMember(name,discountPercent){
this.name = name;
this.discountPercent = discountPercent;
}
function Stock(item){
this.item = item;
}
//Global Variables
var staffMembers = {};
var sally = new StaffMember("Sally",0.05);
staffMembers['sally'] = sally;
var bob = new StaffMember("Bob",0.10);
staffMembers['bob'] = bob;
var me = new StaffMember("Aaron",0.20);
staffMembers['me'] = me;
//item variables
var eggs = new Stock("Eggs");
var milk = new Stock("Milk");
var magazine = new Stock("Magazine");
var chocolate = new Stock("Chocolate");
//item Objects
var Stock = {};
Stock['eggs'] = eggs;
Stock['milk'] = milk;
Stock['magazine'] = magazine;
Stock ['chocolate'] = chocolate;**
var cashRegister = {
total:0,
lastTransactionAmount: 0,
add: function(itemCost){
this.total += (itemCost || 0);
this.lastTransactionAmount = itemCost;
},
scan: function(item,quantity){
switch (item){
case "eggs": this.add(0.98 * quantity); break;
case "milk": this.add(1.23 * quantity); break;
case "magazine": this.add(4.99 * quantity); break;
case "chocolate": this.add(0.45 * quantity); break;
}
return true;
},
voidLastTransaction : function(){
this.total -= this.lastTransactionAmount;
this.lastTransactionAmount = 0;
},
// Create a new method applyStaffDiscount here
applyStaffDiscount : function(employee){
this.total -= this.total*(employee.discountPercent);
}
};
$(document).ready(function(){
$('#target2').hide();
$('#check').on('click', function(e){
e.preventDefault();
var item = $('#item').val();
var quantity = $('#quantity').val();
var staff = $('#staff').val();
cashRegister.scan(item, quantity);
//ERROR IN CODE NOT BYPASSING
if(item === Stock['item'] && quantity > 0) {
cashRegister.scan(item, quantity);
}
///
else {
alert("This Item Does Not Exist!");
}
if(staff.length > 0 && typeof staffMembers[staff] !='undefined'){
cashRegister.applyStaffDiscount(staffMembers[staff]);
}
var output = document.getElementById("result");
result.innerHTML = 'Your bill is ' + cashRegister.total.toFixed(2);
$('#target2').fadeIn(5000)
// .animate({opacity: 0.5}, 3000)
.fadeOut(5000);
});
$('#target').submit(function(){
var info = $(this).serializeJSON();
console.log(info);
var data = JSON.parse('[info]');
console.log(data);
return false;
});
});
Stock['item'] is going to return undefined because Stock['item'] is not declared. You declare Stock['milk'], Stock['magazine'],Stock['eggs'], and Stock['chocolate'], but not Stock['item']. If you were trying to use it as a variable, you should remove the quotes.
You are also overwriting your "Stock" function with a "Stock" object, which is not causing trouble right now but it could cause issues later down the line. You should rename those to be different if possible.
Try using Stock[item] !== undefined && quantity > 0 in place of your current if expression
You did not post your HTML or a working fiddle, but my guess is your if statement should be:
if(item === Stock[item] && quantity > 0) {
cashRegister.scan(item, quantity);
}
Stock['item'] returns undefined as you're not calling it either with an object context like obj.Stock() or after using bind or call, so this is undefined. It's not returning anything either, so no assignment is made. I'm assuming $('#item').val() also. $('#item') is most likely null, triggering a runtime error and stopping your if sentence.

Categories

Resources