error in making JSON in JavaScript - javascript

I am trying to make a JSON, but get a type error.
The error says, cannot set property 'apps' of undefined. This happens at the *.isFav = true
statement. If I remove the if statement it works ( the isFavt(*) statement).
Any help will be appreciated. Thanks!
pref.userid = username;
//systems
systems = [];
for(i=0;i<system.length;i++)
{
systems[i] = new Object();
systems[i].systemid = system[i];
systems[i].apps = [];
j = 0;
$('.save label').each(function ()
{
lst = $(this).text();
console.log(systems[i]);
systems[i].apps[j] = new Object();
systems[i].apps[j].name = lst;
systems[i].apps[j].href= findHref(lst.toLowerCase().replace(/ /g,'_'));
//seq
systems[i].apps[j].seq = j;
//check for favourites
if(isFavt(lst))
systems[i].apps[j].isFav = 'true';
else
systems[i].apps[j].isFav = 'false';
//check for default
if(isDef(lst) == true)
systems[i].apps[j].isDef = 'true';
else
systems[i].apps[j].isDef = 'false';
//subapps
j = j + 1;
});
}
pref.systems = systems;
return pref;
}

Most likely, your isFavt() function has a loop in it, that overwrites the i variable. JavaScript has no block scope and uses global scope if you do not declare your variables with var.
Replace
for(i=0;i<system.length;i++)
with
for(var i=0;i<system.length;i++)
and do the same in your isFavt function, because that is where the error comes from. Actually, do it with every variable you expect to be local to your function inside all your code.
Also, I highly recommend reading up on scoping in JavaScript.

Related

Error with data for each row function problem with brackets and colons

Hello I am new to the community and I am a novice coder with very little coding experience. I understand some basics and 1st part of the code is working. I am having a problem with the data.foreach(funtion(row) where it is giving a error with brackets and colons
function myFunction() {
var Name = 1;
var Surname = 2;
var AffilliateID = 24;
var emailTemp = HtmlService.createHtmlOutputFromFile("Affiliate email");
}
var ws = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Affiliate Responses");
var data = ws.getDataRange("A4:Y" + ws.getLastRow()).getDisplayValues();
data.forEach(function(row) **(**
emailTemp.Name = row[Name]**;**
emailTemp.Surname = row[Surname];
emailTemp.AffilliateID = row[AffiliateID];
))
I have created a var for each line and the tutorial I am following expresses the code as is above. The tutorial may be outdated and some help with an explanation would be appreciated. The bold is the errors.
Thanks
Glenn
For your loop it's something like that
data.forEach(row => {
emailTemp.Name = row[Name]
emailTemp.Surname = row[Surname];
emailTemp.AffilliateID = row[AffiliateID];
})
But to use your
var Name = 1;
var Surname = 2;
var AffilliateID = 24;
var emailTemp = HtmlService.createHtmlOutputFromFile("Affiliate email");
You have to be in the same scope
you need to declare correctly the function that you are passing as a parameter to forEach
const data = [2,5,1,3,4]
data.forEach(function myFunction(item){
console.log(item)
})
you can also use arrow functions:
const data = [2,5,1,3,4]
data.forEach(item => console.log(item))
Welcome to the community. This seems like a simple syntax issue.
You're using ( & ) brackets for function braces, when infact they should be { & } (like your first function).
It's also important that your variables in the right scope. You cannot access the emailTemp variable as it is scoped to your myFunction function. I've moved this into the global scope for you.
Your updated code would look something like this:
function myFunction() {
var Name = 1;
var Surname = 2;
var AffilliateID = 24;
}
var emailTemp = HtmlService.createHtmlOutputFromFile("Affiliate email");
var ws = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Affiliate Responses");
var data = ws.getDataRange("A4:Y" + ws.getLastRow()).getDisplayValues();
data.forEach(function(row) {
emailTemp.Name = row[Name];
emailTemp.Surname = row[Surname];
emailTemp.AffilliateID = row[AffiliateID];
});

Passing values from an object inside a function

I have been working all day trying to pass the value of "returnData.salary" inside the "readData" function to
the object inside the "calculateTax" function which is suppose to take the salary value and calculate state and federal taxes. I am stumped, I can't find anything on the internet which provides a good example for me to work with. The examples are either way to simple or super complex. Any help would be appreciated.
I apologize in advance if I did not submit this question in the correct format. This is my first time asking for help on stackoverflow.
function readForm() {
var returnData = {};
returnData.name = $("#name").val();
returnData.lastName = $("#lastName").val();
returnData.age = $("#age").val();
returnData.gender = $("[name=gender]:checked").val();
returnData.salary = $("#salary").val();
returnData.isManager = $("#isManager").val();
returnData.myTextArea = $("#myTextArea").val();
$("#name2").text(returnData.name);
$("#lastName2").text(returnData.lastName);
$("#age2").text(returnData.age);
$("#gender2").text(returnData.gender);
$("#salary2").text(returnData.salary);
$("#myTextArea2").text(returnData.myTextArea);
if ($(isManager).is(':checked')) {
$("#isManager2").text("Yes");
}
else {
$("#isManager2").text("No");
}
//$("#employeeForm")[0].reset();
} //end of readForm function
function calculateTax() {
console.log("Button Works");
var calculateTax = {
state: function(num) {
num *= 0.09;
return num;
}
, federal: function(num) {
if (num > 10000) {
num *= 0.2;
return num;
}
else {
num * 0.1;
return num;
}
}
, exempt: true
};
}
//Invoke readForm function when the submit button is clicked.
$(document).ready(function () {
$("#btnSubmit").on("click", readForm);
$("#btnCalculate").on("click", calculateTax);
})
</script>
Well, simply put; you can't. Not like this anyway. Or, at least not pass the value to the function directly.
You are using global functions right now, which are not inside a class. If it was inside a class, you could instantiate the class and save it to this (which would be the class' instance). However, I'm assuming classes are a bit over complicated in this case. What you could do, is set variables globally so all functions can use them, like this;
//declare the global variable so it exists for every function
var returnData = {};
function readForm() {
//We do NOT redeclare the "var" again. It's global now.
returnData = {}; //Reset the global variable when this function is called
returnData.name = $("#name").val();
returnData.lastName = $("#lastName").val();
returnData.age = $("#age").val();
returnData.gender = $("[name=gender]:checked").val();
returnData.salary = $("#salary").val();
returnData.isManager = $("#isManager").val();
returnData.myTextArea = $("#myTextArea").val();
//Rest of your function
}
function calculateTax(){
console.log(returnData) //works here
}
Note that you do overwrite global variables, so it's best to reset them on every function call. You might get old data stuck in there, otherwise.

Local variable lost in closure

The variable cont is being lost in the following:
__factory.setupMenu = function(cont,input,multiSelect,exclusive,popMenu){
var __menu = {multiSelect:multiSelect};
spotter.events.setEventTrigger(input,'change');
__menu.exclusive = {inputs:[],values:exclusive||[],simpleValues:[]};
alert(cont);//<-- is defined here
window.popSelectComponent= cont;//<-- saved it globally to test reference
return function(ajaxResult){
var data = ajaxResult.template.response||[];
var info = {},l=data.length;
while(--l > -1){
info[String(data[l].value)] = data[l].abbr||data[l].name;
}
var textTarget;
alert(window.popSelectComponent);//<-- this is defined as expected
alert(cont);//<-- is now undefined
alert(input);//<-- this is defined as expected
if(!(textTarget = cont.querySelector('[data-pop-selected]'))){textTarget = cont;}
if(!input.popSelectTemplate){
spotter.data.bindElementToInput(textTarget,input,function(content){
content = content.split(',');
var l=content.length;
while(--l > -1){
content[l] = info[content[l]];
}
content = content.join(',');
return (content.length ? content : 'ignore');
});
}
else{
var cont = document.createElement('SPAN');//<-- PROBLEM IS CAUSED HERE. HOISTING IS CAUSING CONT TO BE UNDEFINED AT CLOSURE START
cont.className="multi-select";
cont.appendChild(cont);
//removal function
var remove = (function(input){
return function(e){
var evt = e ? e:window.event;
if (evt.stopPropagation) evt.stopPropagation();
if (evt.cancelBubble!=null) evt.cancelBubble = true;
if(input.value !== input.spotterPopSelectDefaultValue){
input.value = input.value.removeListValue(this.getAttribute('data-id'),',');
spotter.deleteElement(this);
if(input.value === '' && input.value !== input.spotterPopSelectDefaultValue){
input.value = input.spotterPopSelectDefaultValue;
input.eventTriggers['pop-select-change']();
}
}
};
}(input));
input.spotterPopMenuOptions = __menu;
input.addEventListener('pop-select-change',(function(cont, info, template){
return function(){
var HTML = '';
this.value.split(',').forEach(function(val){
HTML += template.replace('$[ID]', val).replace('$[NAME]', info[val]);
});
cont.innerHTML = HTML;
spotter.castToArray(cont.children).forEach(function(el){ console.log('option el',el); el.addEventListener('click',remove,false); });
console.log('input.spotterPopMenuOptions',input.spotterPopMenuOptions);
};
}(cont, info, input.popSelectTemplate.innerHTML)),false);
}
....
So running var func = __factory.setupMenu(...)({template:{}}) I am receiving an error message that cont is undefined while window.popSelectComponent is defined like expected. I tried changing the name of cont thinking I was overlooking something that was changing the value but that did not work either.
After running the function, I check cont in the context that initially created this closure and cont is still defined so it is not a matter of an object reference being lost as far as I can tell.
Perhaps a highly simplified example would make the problem more obvious:
var outer = function(theVariable) {
console.log("In the outer function, theVariable is", theVariable);
var inner = function() {
console.log("In the inner function, theVariable is", theVariable);
if (false) {
var theVariable = 2;
}
};
inner();
}
outer(1)
In the outer function, theVariable is 1
In the inner function, theVariable is undefined
As you have seen, the fact that a different variable with the same name has been declared (even though not initialized) in the inner function hides the properly initialized variable in the outer function that would have otherwise been visible.
You might think that because the variable is declared in a block, it would not affect other parts of the function. No, var is function scoped, not block scope.
This flaw has been addressed in modern versions of Javascript, and the var keyword has been superseded by let, which has the block scope you were expecting. var is kept for backwards compatibility, but you should not use it in new code.

Javascript variable inheritance issue

I am having an issue with some code which I would expect to work. I have a variable defined outside a function and as such would expect that to be available to the function through inheritance. I console log the variable outside the function and get a value and console log inside the function and get undefined. I have used comments in the code to show these console logs. Any help here would be great. Please see code snippet below. Thanks Ant
for (var i = 0; i < parseResult.length; i++) {
var destination = parseResult[i].attributes.userInfo;
for (var i = 0; i < firebaseResult.length; i++) {
if (firebaseResult[i].$id == parseResult[i].attributes.facebookID) {
parseResult[i].attributes.convoID = firebaseResult[i].convoID;
console.log(firebaseResult[i].time); // this returns the timestamp value
parseResult[i].attributes.lastMessage = FirebaseAPI.getLastMessage(firebaseResult[i]).$loaded()
.then(function(lastMessage) {
console.log(firebaseResult[i].time); // this returns undefined
if (!(0 in lastMessage)) {
var returnValue = 'Matched on ' + firebaseResult[i].time;
} else if (0 in lastMessage) {
var returnValue = lastMessage[0].message;
}
return returnValue;
})
.catch(function(error) {
console.log("Error:", error);
})
}
}
}
It is often not reliable to use loop iterator to access things in async callback, because when the callback come back, i would have been increased to the value that let it exit the loop.
The fix is assigning it to a variable for anything you want to hold.
console.log(firebaseResult[i].time); // this returns the timestamp value
var time = firebaseResult[i].time;
parseResult[i].attributes.lastMessage = FirebaseAPI.getLastMessage(firebaseResult[i]).$loaded()
.then(function(lastMessage) {
console.log(firebaseResult[i].time); // this returns undefined
console.log(time);
It's because you're in the callback of your FirebaseAPI.getLastMessage() call. If you log this (your scope) in it, you'll get something like a FirebaseAPI object or something.
What you can do is the classic var self = this; trick to keep your context stored in a variable accessible through scopes.
This would look like:
for (var i = 0; i < parseResult.length; i++) {
var destination = parseResult[i].attributes.userInfo;
for (var i = 0; i < firebaseResult.length; i++) {
if (firebaseResult[i].$id == parseResult[i].attributes.facebookID) {
parseResult[i].attributes.convoID = firebaseResult[i].convoID;
console.log(firebaseResult[i].time); // this returns the timestamp value
// Store your context here
var self = this;
this.results = firebaseResult[i].time;
parseResult[i].attributes.lastMessage = FirebaseAPI.getLastMessage(firebaseResult[i]).$loaded()
.then(function(lastMessage) {
console.log(firebaseResult[i].time); // this returns undefined
// Get your values
console.log(this.results); // this returns your values.
if (!(0 in lastMessage)) {
var returnValue = 'Matched on ' + firebaseResult[i].time;
} else if (0 in lastMessage) {
var returnValue = lastMessage[0].message;
}
return returnValue;
})
.catch(function(error) {
console.log("Error:", error);
})
}
}
}
I see in your tags that you're using Angularjs, so you could use the $scope object to store your scope variable and easily deal with promises and such.
Hope this helps :)

Javascript constructor copies array as empty when it should contain items

My code:
function BayesNet(vars) {
this.variables = {};
this.numVars = Object.keys(this.variables).length;
for (v in vars) {
this.variables[v] = new BayesNode(vars[v]);
this.variables[v].CPTorder = this.generateDomainRows(this.variables[v].parents);
this.variables[v].fullCPT = {}
for (var i = 0; i < this.variables[v].CPTorder.length; i++) {
this.variables[v].fullCPT[this.variables[v].CPTorder[i]] = this.variables[v].CPT[i];
}
this.variables[v].blocks = false;
}
}
function BayesNode(obj) {
this.parents = obj.parents;
this.children = obj.children;
if (typeof obj.domain == 'undefined')
this.domain = ['T','F'];
else
this.domain = obj.domain;
this.observation = obj.observation;
this.CPT = obj.CPT;
this.sampleDistribution = [];
for (var i = 0; i < this.CPT.length; i++) {
var s = [];
if(this.CPT[i].length == this.domain.length - 1)
this.CPT[i].push(1 - sumArray(this.CPT[i]));
s.push(this.CPT[i][0]);
for (var j = 1; j < this.domain.length - 1; j++) {
s.push(this.CPT[i][j]+s[j-1]);
}
s.push(1.0);
this.sampleDistribution.push(s);
}
//TODO: Check if CPT is valid
}
My problem is that BayesNode.parent is copied incorrectly.
BayesNode.parent should be an array containing items, and when I run the debugger through the constructor, this.parents is the correct value . However, once I go back to the BayesNet constructor, parents is an empty array. What could be causing this? All other variables in the object behave as expected.
Javascript executes function calls asynchronously. This is the root cause of your issue. You should use callbacks to execute code that is dependent on results of function calls.
Let me explain this using your code:
this.variables[v] = new BayesNode(vars[v]);
this.variables[v].CPTorder = this.generateDomainRows(this.variables[v].parents);
When you call the constructor, JS does NOT wait for the function to finish executing before moving onto the next line of code. When JS comes across "this.variables[v].parents", it is empty, because, the function call in the previous line is still executing asynchronously.
Javascript code design requires a different approach as compared to most other languages.
I don't see any issues in your code, its strange why its becoming empty. but to solve the problem there is a way. change the code as follow.
after this line
this.variables[v] = new BayesNode(vars[v]);
Add the follow
this.variables[v].parents = vars[v].parents;
I see you are not modifying the parents in the constructor, it will work for time being before you find out whats happening. you might have done this already :)

Categories