Javascript type mismatch error - javascript

I have the following code and i am unsure why i am getting the error `Type mismatch'
If i simply have the following, it works;
Working code
newTag = tags.AddNew( 'MyTag0', 'Number0' );
newTag.Update();
Code that returns an error
var p = {
"MyTag0" : "Number0",
"MyTag1" : "Number1"
};
for (var key in p) {
if (p.hasOwnProperty(key)) {
newTag = tags.AddNew("'" + key + "'" + " , " + "'" + p[key] + "'");
newTag.Update();
}
}

They are already strings, you do ont have to build up a string to try to look like a string.
newTag = tags.AddNew("'" + key + "'" + " , " + "'" + p[key] + "'");
What the above code results in is
newTag = tags.AddNew( "'MyTag0'", "'Number0'" );
It just needs to be
newTag = tags.AddNew(key, p[key]);

Use Something like this :
if (p.hasOwnProperty(key)) {
var k = "'" + key + "'";
var pk = "'" + p[key] + "'";
newTag = tags.AddNew(k, pk);
newTag.Update();
}
Another Idea ( not able to debug but you can try..)

Related

How to store data correctly to Firebase Realtime Database

I am creating a google add-on that extracts info from the form. I was able to grab the data and store it in a JSON object. However, when I upload the results to Firebase Realtime Database, it stores weirdly (refer to the screenshot below).
The following is how I would like to upload the data to Firebase:
The following is the code where I create the JSON object. Any help would be appreciated.
function makeJSON(form_title, ques_type, form_question, number_of_choices, multi_options, multi_answer, checkBox_options, checkBox_answer, number_of_questions) {
let type_of_question = ques_type.split("~ ");
let questions = form_question.split("~ ");
let mult_options = multi_options.split("~ ");
let mult_answer = multi_answer.split("~ ");
let check_options = checkBox_options.split("~ ");
let check_answer = checkBox_answer.split("~ ");
let multi_answer_list = [];
let checkbox_answer_list = [];
var newDate = new Date();
var dateAdded = newDate.toLocaleString("en-US");
let jsonObj = "{";
//stores and formats forms data in json object
for(var i = 0; i < number_of_questions; i++){
if(i < number_of_questions){
var count = number_of_choices[i]
jsonObj += '"' + [i+1] + '"' + ":{" + '"question-type"' + ":" + '"' + type_of_question[i] + '",' + '"question"' + ":" + '"' + questions[i] + '",';
for (var k = 0; k < count; k++) {
if(type_of_question[i] === "Multiple Choice"){
jsonObj += '"' + "option" + [k+1] + '"' + ":" + '"' + mult_options[k] + '"' + ",";
}
if(type_of_question[i] === "CheckBox"){
jsonObj += '"' + "option" + [k+1] + '"' + ":" + '"' + check_options[k] + '"' + ",";
}
}
for (var j = 0; j < count; j++) {
if(type_of_question[i] === "Multiple Choice"){
if(mult_answer[j].trim().toLowerCase() === 'true'){
multi_answer_list.push(mult_options[j]);
//jsonObj += '"' + "answer" + [j+1] + '"' + ":" + '"' + mult_options[j] + '"' + ",";
}
}
if(type_of_question[i] === "CheckBox"){
if(check_answer[j].trim().toLowerCase() === 'true'){
checkbox_answer_list.push(check_options[j]);
//jsonObj += '"' + "answer" + [j+1] + '"' + ":" + '"' + check_options[j] + '"' + ",";
}
}
}
if(i < number_of_questions){
if(type_of_question[i] === "Multiple Choice"){
jsonObj += '"' + "answer" + '"' + ":" + '"' + multi_answer_list.join(",") + '"' + ",";
}
if(type_of_question[i] === "CheckBox"){
jsonObj += '"' + "answer" + '"' + ":" + '"' + checkbox_answer_list.join(",") + '"' + ",";
}
}
if(type_of_question[i] !== "Multiple Choice" && type_of_question[i] !== "CheckBox"){
jsonObj += '"' + "answer" + '"' + ":" + '"false"' + ","; //default value
}
if(i < number_of_questions-1){
jsonObj += '"' + "date added" + '"' + ":" + '"' + dateAdded + '"' + "},"; //default value
} else{
jsonObj += '"' + "date added" + '"' + ":" + '"' + dateAdded + '"' + "}"; //default value
}
}
}
jsonObj += "}";
console.log(jsonObj);
sendExtractedData(form_title, jsonObj)
}
UPDATE: The following is the approach that I decided to go with (using push()). I was not able to get the structure (screenshot above) but this is close to what I am looking for:
function makeJSON(form_title, type_of_question, questions, multi_options, multi_answer, checkBox_options, checkBox_answer, number_of_questions) {
var dateAdded = new Date().toLocaleString("en-US"), quesList;
let multiple_option = [], checkbox_option = [], multiple_answer = [], checkbox_answer = [], constructedJSON = {};
var uniqueQuizID = Utilities.getUuid(), num, x;
/** set list of options and answers **/
for(var k = 0; k < multi_options.length; k++){
multiple_option.push(multi_options[k]);
if(multi_answer[k]){
multiple_answer.push(multi_options[k]);
}
}
for(var j = 0; j < checkBox_options.length; j++){
checkbox_option.push(checkBox_options[j]);
if(checkBox_answer[j]){
checkbox_answer.push(checkBox_options[j]);
}
}
/****/
console.log(uniqueQuizID);
constructedJSON.quiz_title = form_title;
//stores and formats forms data in json object
for(var i = 0; i < number_of_questions; i++){
if(type_of_question[i].trim() === "Multiple Choice"){
quesList = {"item-type":type_of_question[i], "question":questions[i], "question-options":multiple_option, "question-responses":multiple_answer, "question-submitted":dateAdded};
x= i+1;
num = ''+ x;
constructedJSON[num] = quesList;
} else if(type_of_question[i].trim() === "CheckBox"){
quesList = {"item-type":type_of_question[i], "question":questions[i], "question-options":checkbox_option, "question-responses":checkbox_answer, "question-submitted":dateAdded};
x= i+1;
num = ''+ x;
constructedJSON[num] = quesList;
} else{
quesList = {"item-type":type_of_question[i], "question":questions[i], "question-submitted":dateAdded};
x= i+1;
num = ''+ x;
constructedJSON[num] = quesList;
}
}
//console.log(constructedJSON);
sendExtractedData(uniqueQuizID, constructedJSON);
}
This construct in your code:
jsonObj += '"' + [i+1] + '"' + ":{"...
Is just a very convoluted way to construct an array without an element at the 0th index. Firebase will store it as a JSON object with sequential numeric keys, and then coerce it back to an array when you read it.
I recommend:
Either storing it as an actual array with jsonObj[i+1] = '"' + ":{"
Or using keys that are not just numbers: ``jsonObj['key_'+(i+1)] = ...`, to prevent Firebase from coercing it into an array.
And either way I'd strongly recommend to:
Don't use string concatenation to construct a JSON object. At best it is just harder to read, but it's actually really easy to make a mistake in there.
This entire line:
jsonObj += '"' + [i+1] + '"' + ":{" + '"question-type"' + ":" + '"' + type_of_question[i] + '",' + '"question"' + ":" + '"' + questions[i] + '",';
Would be much more readable like this:
jsonObj[i] = { question-type: type_of_question[i], question: questions[i] };
Consider not using an array, but use push() for the keys. For more on why, read Best Practices: Arrays in Firebase.

Cannot read item in nested array?

I have a nested array inside a list like the following:
{total_results, page, results [id, species_guess, observed_on_details {date, week, month, hour, year}]}
I am trying to get just the id, species_guess, and date using forEach.
function observationSummary2(data) {
data.results.forEach(element =>
console.log('#' + data.results.id +
" - " + data.results.species_guess +
' (' + data.results.observed_on_details.date + ')')
);
}
This is saying " Cannot read property 'date' of undefined ". I have tried using a for loop like this and it worked just fine.
for (let i = 0; i < data.results.length; i++) {
console.log('#' + data.results[i].id + " - " + data.results[i].species_guess + ' (' + data.results[i].observed_on_details.date + ')');
}
Can anyone tell me where am I doing wrong here, sorry I am still new at this language.
you should use foreach as follow
function observationSummary2(data) {
data.results.forEach(element =>
console.log('#' + element.id +
" - " + element.species_guess +
' (' + element.observed_on_details.date + ')')
);
}
Instead of
function observationSummary2(data) {
data.results.forEach(element =>
console.log('#' + data.results.id +
" - " + data.results.species_guess +
' (' + data.results.observed_on_details.date + ')')
);
}
Replace "data.results" with "element"
function observationSummary2(data) {
data.results.forEach(element =>
console.log('#' + element.id +
" - " + element.species_guess +
' (' + element.observed_on_details.date + ')')
);
}
More info about "forEach()" here:
https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach

insert values into my json between tags

I have this code:
$json = '[{"data":{"name":"Widget Shop USA","widget_a":300,"widget_b":250},"template":{"name":"<h1 class=\"name\"></h1>","cost":"<span class=\"cost\">Price: $</span>"}}]';
$array = json_decode($json, true);
$widget_a = $array[0]['data']['widget_a'];
$widget_b = $array[0]['data']['widget_b'];
$data_name = $array[0]['data']['name'];
$array[0]['template']['cost'] .= $widget_a + $widget_b;
$array[0]['template']['name'] .= $data_name;
What i am trying to do is to get the $array[0]['template']['cost'] and the $array[0]['template']['name'] and pass them into $json variable between the HTML fragments (h1,span). How can i achieve that?
i try to encode the $array:
$json_new = json_encode($array);
but the variables comes after the HTML fragments...Is there any way to pass it between H1 and SPAN tags?
To the question addressed in you comment, you can loop through a JSON, grab the relevant property and assign it like so:
function mm(obj) {
for (var prop in obj) {
obj.name = "<h2>" + obj.employees[0].firstName +"</h2>";
}
return obj;
}
console.log(mm(json));
Working JSBin https://jsbin.com/sefohu/edit?js,console
You can use:
indexOf and slice
for example:
$widget = $array[0].data.widget_a + $array[0].data.widget_b;
$data_name = $array[0].data.name;
$indexCost = $array[0].template.cost.indexOf('$<');
$array[0].template.cost = $array[0].template.cost.slice(0, $indexCost + 1) + $widget + $array[0].template.cost.slice($indexCost + 1, $array[0].template.cost.length);
$indexName = $array[0].template.name.indexOf('><');
$array[0].template.name = $array[0].template.name.slice(0, $indexName + 1) + $data_name + $array[0].template.name.slice($indexName + 1, $array[0].template.name.length);
alert($array[0].template.name);
alert($array[0].template.cost);
or use temp method:
$temp = document.createElement('template');
$temp.innerHTML = $array[0]['template']['name'];
$temp.getElementsByTagName('h1')[0].innerHTML = $array[0]['data']['name'];
$array[0]['template']['name'] = $temp.innerHTML;
if you can change the json my suggestion:
$json = '[{"data":{"name":"Widget Shop USA","widget_a":300,"widget_b":250},"template":{"nametag":"h1","nameclass":"name","costtag":"span","costclass":"cost"}}]';
and use:
$array = JSON.parse($json);
$widget = $array[0].data.widget_a + $array[0].data.widget_b;
$array[0].template.cost = '<' + $array[0].template.costtag + ' class="' + $array[0].template.costclass + '" >' + $widget + '</' + $array[0].template.costtag + '>';
$array[0].template.name = '<' + $array[0].template.nametag + ' class="' + $array[0].template.nameclass + '" >' + $array[0].template.name + '</' + $array[0].template.nametag + '>';
alert($array[0].template.name);
alert($array[0].template.cost);

If / Else jQuery to skip undefined value

I have this chained select box (demo) using JSON file to populate options based on this script.
Here's the script:
$(window).bind('load', function() {
$.getJSON('suggest.json', function(data){
var $select = $('#mySelectID');
$.each(data, function (index, o) {
var $option = $("<option/>").attr("value", o.Box1ID + ":" + o.Box3).text(o.Box1 + "|" + o.Box2 + "|" + o.Box3);
$select.append($option);
});
$("#mySelectID").dynamicDropdown({"delimiter":"|"});
});
});
I have trouble using if statement to skip undefined value. The JSON file is like this:
[{"Box1":"A","Box1ID":"B","Box3":"C"},{"Box1":"E","Box1ID":"F","Box2":"G","Box3":"H"}]
If Box2 doesn't exist, I want the var $option to be:
var $option = $("<option/>").attr("value", o.Box1ID + ":" + o.Box3).text(o.Box1 + "|" + o.Box3);
Would typeof undefined work here? But I'm not sure what variable should be defined.
if (typeof var?? === 'undefined') {
var $option = $("<option/>").attr("value", o.Box1ID + ":" + o.Box3).text(o.Box1 + "|" + o.Box3); }
else {
$("<option/>").attr("value", o.Box1ID + ":" + o.Box3).text(o.Box1 + "|" + o.Box2 + "|" + o.Box3);
}
Any help would be appreciated. Thank you.
You can also just do this:
if (! data.Box2) {
...
}
Undefined, null, and empty string all test as false in JavaScript.
you can do something like:
... .text(o.Box1 + "|" + (o.Box2?oBox2+"|":"") + (o.Box3||"") );
Use
$(window).bind('load', function() {
$.getJSON('suggest.json', function(data){
var $select = $('#mySelectID');
$.each(data, function (index, o) {
var $option = $("<option/>").attr("value", o.Box1ID + ":" + o.Box3);
if (typeof data.Box2 === 'undefined')
{
$option.text(o.Box1 + "|" + o.Box3);
}
else {
$option.text(o.Box1 + "|" + o.Box2 + "|" + o.Box3);
}
$select.append($option);
});
$("#mySelectID").dynamicDropdown({"delimiter":"|"});
});
});
If you check the typeof of a object method/attribute that does not exists, it will return 'undefined'.

Shorten a method. Syntax better practices

I've been learning via jQuery how to shorten things up. I was wondering if this script can be expressed in a less verbose way? I don't like how everything sits on one huge line.
items.push('<li id="' + key + '">' + ' (key: ' + key + ')(value: ' + val.value + ')(type: ' + val.type + ') (range: ' + val.range + ') (clone: ' + val.clone + ') (archive: ' + val.archive + ') (access: ' + val.access + ')</li>')
Assuming that the object will always have the correct key/values:
str = '';
for (var item in val) {
str += '(' + item + ': ' + val[item] + ')';
}
$("<li>").attr('id', key).text(' (key: ' + key + ')' + str);
http://jsfiddle.net/36Nyu/
If items is another element, you can do something like this.
var str;
for(var i in val)
str += '('+ i +': '+ val[i] +')';
$('<li>', {
id: key,
text: str
}).appendTo(items);
You could use jquery tmpl, or similar:
var template = '(key: ' + key + ')(value: {{value}})(type: {{type}}) (range: {{range}}) (clone: {{clone}}) (archive: {{archive}}) (access: {{access}})';
$('<li />').attr('id', key).html($.tmpl(template, val));
Or, use a string.Format equivalent:
String.prototype.format = function () {
var args = arguments;
return this.replace(/\{\{|\}\}|\{(\d+)\}/g, function (m, n) {
/* Allow escaping of curly brackets with {{ or }} */
if (m === '{{') { return '{'; } else if (m === '}}') { return '}'; }
return typeof args[n] != 'undefined' ? args[n] : '{' + n + '}';
});
};
var text = '(key: {0})(value: {1})(type: {2}) (range: {3}) (clone: {4}) (archive: {5}) (access: {6})'.format(key, val.type, val.range, val.clone, val.archive, val.access);
Assuming you're appending all of the key/value pairs in the val object, doing something like this would be pretty maintainable:
var liPrefix = '<li id="' + key + '">(key: ' + key + ')',
liSuffix = '</li>',
liData = '';
$.each(val, function(k, v) {
liData += ' (' + k + ': ' + v + ')';
});
items.push(liPrefix + liData + liSuffix);
See demo

Categories

Resources