JavaScript objects update function not working - javascript

im studying JavaScript and im trying to solve the problem in this test exercise:
FreeCodeCamp Record Collection
I can't understand why it doesnt work. The object details and the problem description are in the link above.
function updateRecords(object, id, prop, value) {
if (value === '') {
delete object[id][prop];
} else if (prop === 'tracks') {
if (object[id][prop].hasOwnProperty('tracks') == false) {
object[id][prop] = [value];
} else if (value !== '') {
object[id][prop].push(value);
}
} else if (prop !== 'tracks' && value !== '') {
object[id][prop] = value;
}
return object;
}
This is the error i get:
// running tests
After updateRecords(collection, 5439, "tracks", "Take a Chance on Me"), tracks should have Take a Chance on Me as the last element.
After updateRecords(collection, 2468, "tracks", "Free"), tracks should have 1999 as the first element.
// tests completed
Thank you for your support.

Let's take a look at this line:
if (object[id][prop].hasOwnProperty('tracks') == false) {
If we replace the variables with their values, we get:
if (object[5439]['tracks'].hasOwnProperty('tracks') == false) {
^ ^
... which is always going to fail. Here is a simplified version:
function updateRecords(object, id, prop, value) {
if (value === '') {
delete object[id][prop];
} else if (prop === 'tracks') {
if (!object[id].hasOwnProperty('tracks')) {
object[id][prop] = [];
}
object[id][prop].push(value);
} else {
object[id][prop] = value;
}
return object;
}

Related

Checking if a value has not been initialized always returns value is not initialized, even if it is

I am trying to jQuery-like script that supports selectors, show, hide, text, and html methods.
Running a test, no matter which method I call, it always throws a custom "No Element Selected" error. How do I fix this?
The full code is here --> https://jsfiddle.net/7ado13vg/
The relevant code is below
var storingAttributes = {};
class MONEY {
constructer(string) {
try {
//check for action
if (string != null) {
//Check Selection Type
storingAttributes.selectorArray = string.split('')
if (storingAttributes.selectorArray[0] == '#') {
storingAttributes.selectionType = 'id';
storingAttributes.selectorArray.splice(0, 1);
}
if (storingAttributes.selectorArray[0] == '.') {
storingAttributes.selectionType = 'class';
storingAttributes.selectorArray.splice(0, 1);
}
if (storingAttributes.selectorArray[0] != '#' && storingAttributes.selectorArray[0] != '.') {
storingAttributes.selectionType = 'tag';
}
//Select Elem
if (storingAttributes.selectionType == 'id') {
storingAttributes.selectedElem = document.querySelector(string);
}
if (storingAttributes.selectionType == 'class') {
storingAttributes.selectedElem = document.querySelectorAll(string);
}
if (storingAttributes.selectionType == 'tag') {
storingAttributes.selectedElem = document.querySelectorAll(string);
}
}
} catch (error) {
}
}
//The reason I checked what was being selected is because querySelectorAll returns an array, and I do not believe that ids are supported
//trying to use my method 'show'
show() {
try {
if (typeof storingAttributes.selectedElem == 'undefined' || storingAttributes.selectedElem == null) {
throw "No Element Selected";
} else {
if (storingAttributes.selectionType == 'tag') {
for (n = 0; n < storingAttributes.selectedElem.length; ++n) {
storingAttributes.selectedElem[n].style.display = 'block';
}
return;
}
if (storingAttributes.selectionType == 'class') {
for (n = 0; n < storingAttributes.selectedElem.length; ++n) {
storingAttributes.selectedElem[n].style.display = 'block';
}
return;
}
if (storingAttributes.selectionType == 'id') {
storingAttributes.selectedElem.style.display = 'block';
return;
}
}
} catch (e) {
console.log(e);
}
}
}
As you can see, the constructor simply assigns/initializes a value for selectionType, selectedElem, and selectorArray in the object storingAttributes
When you log storingAttributes, it returns an empty object.
The following replaces the code you've posted to show how much simpler it can be written and without erroneously using try/catch.
I understand that it doesn't answer your question, but the code you are working with is really so unnecessarily excessive, it's hard to sift through it to find your problem without refactoring it. Simpler code is easier to debug.
var storingAttributes = {};
// Just test for the non-existance of a value
if (!storingAttributes.selectedElem) {
throw "No Element Selected";
} else {
// switch is more concise when you have a single value to
// check against multiple possible values
switch (storingAttributes.selectionType){
case "tag":
// And since you want to do the exact same code if
// it's "tag" or "class", we'll allow fall through here
case "class":
// The Array.prototype.forEach method makes looping much simpler
storingAttributes.selectedElem.forEach(function(item){
item.classList.add("block");
});
break;
case "id":
storingAttributes.selectedElem.classList.add("block");
}
}
/* Avoid inline styles which lead to duplication of code.
Instead, use CSS classes where possible. */
.block { display:block; }

Foreach loop to check for a value

I have a foreach loop that loops through an array, then im running a callback function with the value of each item in the array as the parameter of the function, which is run once fore very item in the array. In the call back function i am trying to compare the value being passed with a string, but I always get a false nothing gets logged to console
This is my code
window.addEventListener('load', function() {
let occupation = ["urologist", "urologist", "staff", "nurse", "surgeon"]
occupation.forEach(function(occ) {
let ab = occ.textContent
let bc = ab.toLowerCase();
chkfun(bc)
})
function chkfun(val) {
if (val == "urologist") {
console.log("urologist")
}
if (val == "surgeon") {
console.log("surgeon")
}
if (val == "staff") {
console.log("staff")
}
if (val == "nurse") {
console.log("nurse")
}
}
}, false);
Your problem is with the line let ab = occ.textContent. occ contains the text content already. You can just do bc = occ.toLowerCase()
Also take a look at JavaScript Switch instead of doing a bunch of if's
You can call your function inside the forEach and it will be called with each element, there you can transform your value to lowercase and compare, also use a else if so the script will not test each value and stop as soon as it get a match. You can also add a else at the end for unknown elements
window.addEventListener('load', function() {
let occupation = ["Urologist", "urologist", "staff", "nurse", "surgeon","a"];
occupation.forEach(chkfun);
function chkfun(v) {
let val = v.toLowerCase();
if (val == "urologist") {
console.log("urologist")
} else if (val == "surgeon") {
console.log("surgeon")
} else if (val == "staff") {
console.log("staff")
} else if (val == "nurse") {
console.log("nurse")
} else {
console.log("element not found");
}
}
}, false);

Validate empty object

I have an variable that devolves an empty object, and i need validate thas this variable have a value.
guardar: function() {
var value1 = Ext.getCmp('radio1').getValue();
if (value1 === {}) {
alert('It is necessary to select an option.');
return;
}
}
When it arrives in the debug line in the If statement, although the value of the variable is {}, when evaluating the condition the result is false.
¿Someone could help me about how can i do that validation?
If you get a object, then, do you need to proccess that object to verify if exist a property
Try this:
guardar: function() {
var value1 = Ext.getCmp('radio1').getValue();
if (typeof value1 === 'object' && Object.keys(value1).length === 0) {
alert('It is necessary to select an option.');
return;
}
}
guardar: function() {
var value1 = Ext.getCmp('radio1').getValue();
if (Object.keys(value1).length === 0) {
alert('It is necessary to select an option.');
return;
}
} // This Will Work as your requirement
You can't do value1 === {} for the same reason that {} === {} is false. The reason for this is javascript compares objects by reference, not by value. Which means it checks if the objects occupy the same memory location.
You can try something like
Object.prototype.isEmpty = function() {
for(var key in this) {
if(this.hasOwnProperty(key))
return false;
}
return true;
}
Then you can test if it's empty
if (value1.isEmpty()) {
alert('It is necessary to select an option.');
return;
}
function isEmpty(obj) {
for(var key in obj) {
if(obj.hasOwnProperty(key)){
return false;
}
}
return true;
}
var x = {};
if(isEmpty(x)){
alert('It is necessary to select an option.');
return;
}else{
}

Passing the methods hide/show to another method

I am calling an object method in two ways in my code:
this.reveal.updateVisuals(i, 'show');
or
this.reveal.updateVisuals(i, 'hide');
and I am passing the hide and show condition as a string, to be later evaluated and used as a method. Please note the condition: if (effect === 'show/hide').
updateVisuals: function (time, effect) {
// Check if parameter exists and property can be read
if (this.breakpointsMap && typeof this.breakpointsMap[checkTime] !== "undefined") {
if (effect === 'show') {
// display the items that were fast forwarded
var k = this.breakpointsMap[checkTime].length;
while (k--) {
try {
this.breakpointsMap[checkTime][k].show();
} catch (err) {}
}
} else if (effect === 'hide') {
// display the items that were fast forwarded
var k = this.breakpointsMap[checkTime].length;
while (k--) {
try {
this.breakpointsMap[checkTime][k].hide();
} catch (err) {}
}
}
}
}
However the code seems duplicated and I was wondering if there is a way to pass hide or show as a method to the method and apply it on the array, when needed. I tried something like this:
this.reveal.updateVisuals(i).show
There are a lot of ways you can use to simplify this, here are a couple:
updateVisuals: function (time, effect) {
if (this.breakpointsMap && typeof this.breakpointsMap[checkTime] !== "undefined") {
this.breakpointsMap[checkTime].forEach(e => e[effect]());
}
}
Or returning the array:
updateVisuals: function (time, effect) {
if (this.breakpointsMap && typeof this.breakpointsMap[checkTime] !== "undefined") {
return this.breakpointsMap[checkTime];
}else{
return [];
}
}
this.reveal.updateVisuals(i).forEach(e => e.show());
You can access a method property by it's (string) name using [bracket] notation.
updateVisuals: function (time, effect) {
// Check if parameter exists and property can be read
if (this.breakpointsMap && typeof this.breakpointsMap[checkTime] !== "undefined") {
var k = this.breakpointsMap[checkTime].length;
while (k--) {
try {
this.breakpointsMap[checkTime][k][effect]();
} catch (err) {}
}
}
}
if you are using Es6, you can do:
function updateVisuals (time, effect) {
// Check if parameter exists and property can be read
if (this.breakpointsMap && typeof this.breakpointsMap[checkTime] !== "undefined") {
let execFn= (arrindex) => breakpointsMap[checkTime][arrindex].show();
if (effect === 'hide')
{
execFn = (arrindex) => breakpointsMap[checkTime][arrindex].hide();
}
// display the items that were fast forwarded
var k = this.breakpointsMap[checkTime].length;
while (k--) {
try {
execFn(k);
} catch (err) {}
}
}
}
I assume that var checkTime is global or in closure. If you are using version lower tan es6 you can use execFn= function (arrindex) {...}, a then bind this argument when calling method after.

Evaluate passed value using .filter in JavaScript

I have a method that takes a language abbreviation and matches it using a .constant dictionary, and returns the matching language name.
How can I do an evaluation with .filter to check whether the passed isoCode/language abbreviation exists?
Here is my method:
angular.module('portalDashboardApp')
.service('ISOtoLanguageService', ['Languages', function(Languages) {
this.returnLanguage = function(isoCode) {
var categoryObject = Languages.filter(function ( categoryObject ) {
return categoryObject.code === isoCode;
})[0];
return categoryObject.name;
};
}]);
Here is the method with some error catching I have tried:
angular.module('portalDashboardApp')
.service('ISOtoLanguageService', ['Languages', function(Languages) {
this.returnLanguage = function(isoCode) {
var categoryObject = Languages.filter(function (categoryObject) {
if (isoCode != null || isoCode != undefined) {
return categoryObject.code === isoCode;
}
else {
return categoryObject.code === 'und';
}
})[0];
if (categoryObject.name != undefined || categoryObject.name != null) {
return categoryObject.name;
}
else {
return "undefined";
}
};
}]);
Thank you!
I would recommend you organize your data at Languagesin an object or map, it'll be much faster and simpler when you fetch your translation by an abbreviation. A short example:
angular.module('portalDashboardApp')
.factory('Languages', function(){
var dictionary = {
ISO: {name: 'International Organization for Standardization'}
};
return {
get: function(abbr){
return dict[abbr];
}
};
}).service('ISOtoLanguageService', ['Languages', function(Languages) {
this.returnLanguage = function(isoCode) {
if(!isoCode) {
return "Answer for empty isoCode";
}
var categoryObject = Languages.get(isoCode);
return (categoryObject || {}).name || "I don't know this abbr";
};
}]);
I'm not sure that this JS works without any syntax error (I've not try to launch it) but idea is that you don't need array and filter on big dictionaries and you are able to get any abbreviation from dict with O(1) complexity even with huge dictionary.
If you don't want to have a refactoring with your code you can do something like this:
angular.module('portalDashboardApp')
.service('ISOtoLanguageService', ['Languages', function(Languages) {
this.returnLanguage = function(isoCode) {
if (!isoCode) {
return;
}
var resultAbbrs = Languages.filter(function (categoryObject) {
return categoryObject.code === isoCode;
});
if (resultAbbrs.length > 0) {
return resultAbbrs[0].name;
}
};
}]);
In this case if isoCode is null, undefined or empty string or this key is not found in dictionary return undefined will be by default. Outside you should check a result of this function with if (result === undefined) ...
I hope it helped you)

Categories