Shorten a method. Syntax better practices - javascript

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

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

How can I filter null or undefined values from an ajax call?

I'm trying to create a simple class directory for my kid's class. I have a Array of students in JSON format and wrote an AJAX call for the kids' names, and parents information. But some don't have two parents or two sets of contact information? I have tried "if (studentData !== null) {
show the data} but that doesn't work.
function showStudents() {
var currentURL = window.location.origin;
$.ajax({ url: currentURL + '/api/students', method: 'GET'})
.then(function(studentData) {
console.log("------------------------------------");
console.log("URL: " + currentURL + "/api/students");
console.log("------------------------------------");
// Here we then log the NYTData to console, where it will show up as an object.
console.log(studentData);
console.log("------------------------------------");
for (var i = 0; i < studentData.length; i++ ) {
var studentSection = $('<div>');
studentSection.addClass('card');
studentSection.attr('id', 'studentCard-' + i);
studentSection.attr('style', 'width:25rem');
$('#studentSection').append(studentSection);
$('#studentCard-' + i ).append('<div class="card-header"><h3>' + studentData[i].firstName + ' ' + studentData[i].lastName + '</h3></div>');
$('#studentCard-' + i ).append('<ul class="list-group list-group-flush>');
$('#studentCard-' + i ).append('<li class="list-group-item"><h5>Parent(s):</h5>' + studentData[i].parent1 + ' & ' + studentData[i].parent2 +' </li>');
$('#studentCard-' + i ).append('<li class="list-group-item">' + 'phone: ' + studentData[i].contact1 + '<br> email: ' + studentData[i].email1 + '</li>');
$('#studentCard-' + i ).append('<li class="list-group-item">' + 'phone: ' + studentData[i].contact2 + '<br> email: ' + studentData[i].email2 + '</li>');
$('#studentCard-' + i ).append('</ul>');
$('#studentCard-' + i ).append('</div>');
}
});
}
It sounds like it's the parent1 or parent2 properties that might not exist, and the contact1 or contact2 properties that might not exist. It doesn't make sense to test if the entire response is null - just check those properties instead. For example:
for (var i = 0; i < studentData.length; i++ ) {
var studentSection = $('<div>');
studentSection.addClass('card');
studentSection.attr('id', 'studentCard-' + i);
studentSection.attr('style', 'width:25rem');
$('#studentSection').append(studentSection);
$('#studentCard-' + i ).append('<div class="card-header"><h3>' + studentData[i].firstName + ' ' + studentData[i].lastName + '</h3></div>');
$('#studentCard-' + i ).append('<ul class="list-group list-group-flush>');
// Start of changes
const parentStr = [studentData[i].parent1, studentData[i].parent2].filter(Boolean).join(' & ');
$('#studentCard-' + i ).append('<li class="list-group-item"><h5>Parent(s):</h5>' + parentStr +' </li>');
if (studentData[i].contact1) {
$('#studentCard-' + i ).append('<li class="list-group-item">' + 'phone: ' + studentData[i].contact1 + '<br> email: ' + studentData[i].email1 + '</li>');
}
if (studentData[i].contact2) {
$('#studentCard-' + i ).append('<li class="list-group-item">' + 'phone: ' + studentData[i].contact2 + '<br> email: ' + studentData[i].email2 + '</li>');
}
// End of changes
$('#studentCard-' + i ).append('</ul>');
$('#studentCard-' + i ).append('</div>');
}
Your script structure could be improved too - unless each card's id is particularly important, it would make more sense to use a class instead of unique ids for every single element, or perhaps to leave it off entirely if you're only using it to select the newly created container. You already have a reference to the element you just created with studentSection, so just reference that variable again. You can also use method chaining to reduce your syntax noise:
CSS:
.card {
width: 25rem;
}
(that will keep you from having to manually set the width of each created element in your JS)
JS loop:
for (var i = 0; i < studentData.length; i++ ) {
var studentSection = $('<div>');
$('#studentSection').append(studentSection);
const parentStr = [studentData[i].parent1, studentData[i].parent2].filter(Boolean).join(' & ');
studentSection.addClass('card')
.append('<div class="card-header"><h3>' + studentData[i].firstName + ' ' + studentData[i].lastName + '</h3></div>')
.append('<ul class="list-group list-group-flush>')
.append('<li class="list-group-item"><h5>Parent(s):</h5>' + parentStr +' </li>');
if (studentData[i].contact1) {
studentSection.append('<li class="list-group-item">' + 'phone: ' + studentData[i].contact1 + '<br> email: ' + studentData[i].email1 + '</li>');
}
if (studentData[i].contact2) {
studentSection.append('<li class="list-group-item">' + 'phone: ' + studentData[i].contact2 + '<br> email: ' + studentData[i].email2 + '</li>');
}
studentSection.append('</ul>');
.append('</div>');
}
(Or, even better, use template literals instead)

Prettify stringified object in javascript to serve in a static html page

I'm trying to use this code to prettify a JSON object retrieved from another service and return it in a static page (has to be).
The javascript functions work but I'm having issues dealing with the stringified object.
It works fine encoding for example before the return statement for the html
json = "{\"a\":\"b\",\"c\":\"d\"}"
and not using stringify but it does not using JSON.stringify with a real JSON object instead.
function getStaticResponse(jsonObjectRetrieved){
return '<html>'
+ '<head>'
+ '<title>' + 'title' + '</title>'
+ '<link rel="stylesheet" type="text/css" href="'
+ '/something' + '">'
+ '</head>'
+ '<body>'
+ '<pre class="json-output box bg-color-weight-6 font-calibri">'
+ jsonFormat(JSON.stringify(jsonObjectRetrieved))
+ '</pre>'
+ '</body>'
+ '</html>';
}
function transformJson(k, v) {
if (k === 'href' && typeof v === 'string') {
var label = v.replace(/&/gi, '&');
return '<a href=' + v + '>' + label + '</a>';
}
return v;
}
function jsonFormat(jsonString) {
var jsonObj = JSON.parse(jsonString, transformJson);
return JSON.stringify(jsonObj, undefined, 2)
.replace(/\s"(\w*)":/g, ' "<span class="key">$1</span>":')
.replace(/:\s"(.*)"/g, ': "<span class="string">$1</span>"');
};
Many thanks
Try removing call to JSON.stringify at jsonFormat(JSON.stringify(jsonObjectRetrieved))
var json = "{\"a\":\"b\",\"c\":\"d\"}";
function getStaticResponse(title, jsonObjectRetrieved) {
return '<html>'
+ '<head>'
+ '<title>' + title + '</title>'
+ '<link rel="stylesheet" type="text/css" href="'
+ 123 + '">'
+ '</head>'
+ '<body>'
+ '<pre class="json-output box bg-color-weight-6 font-calibri">'
+ jsonFormat(jsonObjectRetrieved)
+ '</pre>'
+ '</body>'
+ '</html>';
}
function transformJson(k, v) {
if (k === 'href' && typeof v === 'string') {
var label = v.replace(/&/gi, '&');
return '<a href=' + v + '>' + label + '</a>';
}
return v;
}
function jsonFormat(jsonString) {
var jsonObj = JSON.parse(jsonString, transformJson);
return JSON.stringify(jsonObj, null, 2)
.replace(/\s"(\w*)":/g, ' "<span class="key">$1</span>":')
.replace(/:\s"(.*)"/g, ': "<span class="string">$1</span>"');
};
document.write(getStaticResponse("abc", json));

Javascript type mismatch error

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

Categories

Resources