SCRIPT5007: Unable to get property 'toLowerCase' of undefined or null reference - javascript

I have a .aspx file working on SharePoint.
We are using IE11, jQuery 2.2.3, jQuery UI 1.11.4, Bootstrap 3.3.6
We had this system for around three years by a third party, which we stopped business. And not able to contact anymore.
It was working fine until a few weeks ago suddenly the page is loading forever and showing this error
SCRIPT5007: Unable to get property 'toLowerCase' of undefined or null reference
Loading page - capture
I have Googled and it seems like the script is waiting for ConfigurationCube.js to load. But since it's not loading, I think it's waiting forever.
/* handles the displaying of all outstanding items requiring approval*/
var TableCreated=0;
var app="";
var teamsArr = [];
var GlobalDivisionsArr = [];
$(document).ready(function(){
//check to see if the Configuration cube Obj Exists and wait until it does
var checkExist = setInterval(function() {
if (sessionStorage["ConfigurationCube"] != null) {
app = JSON.parse(sessionStorage.ConfigurationCube).AppURL;
/**CreateLookupSectionForEmployees("My Winners","Kaizen List","#ViewWinnersTable");**/
//Displayed using the configuration cube.js file
DisplayUserInformation();
popDD("kznSearchCategory",JSON.parse(sessionStorage.ConfigurationCube).ListOfCategories);
IntialPopulationOfApprovedKaizens("","Kaizen List","#kznSearchResultsTable");
//Initialize date range picker
/**$("#kznEditToDate").datepicker();*/
var CubeMin = (JSON.parse(sessionStorage.ConfigurationCube).SubmissionPeriod).split(" ")[0];
clearInterval(checkExist);
}
}, 500);
});
I also tried in IE8, 9, 10, Edge. All not working.
Our company does not allow Chrome or any other browser so we need to get it work in IE..
My current meta tag is like this. Also tried various ways, but did not work.
<meta http-equiv="x-ua-compatible" content="IE=edge; charset=UTF-8">
Does anyone have any similar problems?
Any kind of idea is appreciated..
When clicking on the error, it directs to ConfigutationCube.js
//Tools for other pages
function compareStrings(a, b) {
// Assuming you want case-insensitive comparison
a = a.toLowerCase();
b = b.toLowerCase();
return (a < b) ? -1 : (a > b) ? 1 : 0;
}
Script snip from SearchKaizen.js
function IntialPopulationOfApprovedKaizens(HeadingTitle,ListName,ElementToAppend){
//Get all current data from lists
var GetKaizenPromise = GetList( "Kaizen List",
"Id,Nominated_x0020_person, Status, Kaizen_x0020_Title,Division/Id, Team/Id,Division/Title, Team/Title, Name, Financial_x0020_Year, Kaizen_x0020_Category,Quarter",
"Division/Id, Team/Id,Division/Title, Team/Title",
"Status eq 'Approved'",
app);
$.when(GetKaizenPromise).done(function(KaizenSelectionData){
var EditButton = "";
var Results = KaizenSelectionData.d.results;
//Creates table structure and heading
var DataTableHtml = "";
var SetVotedBackground = "style='background-color:lightgreen;color:white;'";
var DivisionList = [];
var TeamList = [];
var YearList = [];
var DivisionCheck = [];
var TeamCheck = [];
if(Results.length > 0){
for(r=0;Results.length > r;r++){
TableCreated++;
var ResultsName = Results[r].Nominated_x0020_person;
var KaizenTitle = Results[r].Kaizen_x0020_Title;
var ResultsTeam = Results[r].Team.Title;
var ResultsDivision = Results[r].Division.Title;
var ResultsTeamId = Results[r].Team.Id;
var ResultsDivisionId = Results[r].Division.Id;
var ResultsCategory = Results[r].Kaizen_x0020_Category;
var ResultsStatus = Results[r].Status;
var ResultsQuarter = Results[r].Quarter;
var ResultsYear = Results[r].Financial_x0020_Year;
EditButton = "<p style='cursor:pointer;' class='edititem text-light-blue' data-itemid='"+Results[r].Id+"' data-listname='"+ListName+"'><i class='fa fa-edit'></i> View</p>";
DataTableHtml += "<tr>"+
"<td>"+ResultsName+"</td><td>"+ResultsDivision+"</td><td>"+ResultsTeam +"</td>"+
"<td>"+ResultsYear+"</td><td>"+ResultsQuarter+"</td><td>"+KaizenTitle +"</td>"+
"<td>"+ResultsCategory +"</td><td>"+EditButton+"</td>"
"</tr>";
//Create the drop down box info from all the results
if($.inArray(ResultsDivision , DivisionCheck ) == -1){
// Add to departments list
DivisionList.push({"FullName": ResultsDivision,"ID":ResultsDivisionId});
DivisionCheck.push(ResultsDivision);
//Keep duplicate of original divisions list
GlobalDivisionsArr.push({"FullName": ResultsDivision,"ID":ResultsDivisionId});
}
if($.inArray(ResultsTeam , TeamCheck) == -1){
// Add to Teams list
TeamList .push({"FullName": ResultsTeam,"ID":ResultsTeamId,"Division":ResultsDivisionId});
TeamCheck.push(ResultsTeam);
//Keep duplicates of original list
teamsArr.push({"FullName": ResultsTeam,"ID":ResultsTeamId,"Division":ResultsDivisionId});
}
if($.inArray(ResultsYear , YearList) == -1){
// Add to Year list
YearList.push(ResultsYear );
}
//next Item
}
}else{
//if there are no results
DataTableHtml = "<tr>"+
"<td colspan='8'>No results found</td>" +
"</tr>";
}
YearList.sort();
YearList.reverse();
TeamList.sort(function(a, b) {
return compareStrings(a.FullName, b.FullName);
});
DivisionList.sort(function(a, b) {
return compareStrings(a.FullName, b.FullName);
});
popDD("kznSearchYear",YearList);
popDDSearchWithDataAttr("kznSearchTeam",TeamList,TeamList);
DivisionList.unshift({"FullName": "All","ID":"All"}); //Add All option to division list
popDDVal("kznSearchDivision",DivisionList);
//adds items to DOM
$(ElementToAppend + " tbody").html(DataTableHtml);
//Create column match with returned results
if (Results.length>0){
$.fn.dataTable.ext.errMode = 'console';
$(ElementToAppend).DataTable({
"dom": 'ftipr',
"responsive": true
});
}
$("body").css("overflow","");
//removes overlayer and loading symbol
$("#OverlayFade").addClass("hidden");
$("#Timer").addClass("hidden");
});
}
This snip of the script has popDDVal, and it looks like 'DivisionList' 'TeamList' 'YearList' is returning null. Since this is null it can not break from the loading overlayer.
I was able to narrow it down to this part.
TeamList.sort(function(a, b) {
return compareStrings(a.FullName, b.FullName);
});
DivisionList.sort(function(a, b) {
return compareStrings(a.FullName, b.FullName);
});
Changed it to this, and it worked. But obviously the sorting is not sorted correctly, but least it works now...
TeamList.sort();
DivisionList.sort();

Instead of passing in an anonymous function pass the function name:
TeamList.sort(compareStrings);
or
DivisionList.sort(compareStrings);

Related

How to use different blogger post ID in Javascript variable?

I am trying to make every article views having comma separated every 3 digit number. I have found the code for that.
But I have problem to find specific blogger post ID to use for the code to work fine.
Here's the whole code that I am trying to work on.
<--Viewable area /-->
<span class='entry-time'><b:if cond='data:allBylineItems.author and data:allBylineItems.timestamp.label'><span class='on'><data:allBylineItems.timestamp.label/></span></b:if><time class='published' expr:datetime='data:post.date.iso8601'><data:post.date/></time></span><span class='postviews1' style='margin-left:5px; display:display;'><a expr:name='data:post.id'/> <i class='far fa-eye'/> <span id='bacani'><span id='postviews'/></span> Views</span>
<--comma separated every 3 digit /-->
<script>var angka = document.getElementById('bacani').textContent;var reverse = angka.toString().split('').reverse().join(''),ribuan = reverse.match(/\d{1,3}/g);ribuan = ribuan.join(',').split('').reverse().join('');document.getElementById('bacani').innerHTML= ribuan;</script>
<--code for views count /-->
<script src='https://cdn.firebase.com/v0/firebase.js' type='text/javascript'/> <script> $.each($("a[name]"), function(i, e) { var elem = $(e).parent().find("#postviews"); var blogStats = new Firebase("https://sh-v-3da10-default-rtdb.firebaseio.com/" + $(e).attr("name")); blogStats.once("value", function(snapshot) { var data = snapshot.val(); var isnew = false; if(data == null) { data= {}; data.value = 0; data.url = window.location.href; data.id = $(e).attr("name"); isnew = true; } elem.text(data.value); data.value++; if(window.location.pathname!="/") { if(isnew) blogStats.set(data); else blogStats.child("value").set(data.value); } }); });</script>
I want to change:
<span id='bacani'><span id='postviews'/></span>
and
document.getElementById('bacani').textContent;
to have a specific value id which is post id from blogger. The only thing that i found from internet is
<data:post.id>
Is there any other way that i can make it work other than what I am thinking right now? I think I need specific new id to make it work for every article to have comma separated every 3 digit.
I try to use the code but it only work for one time only. I believe to make it work as a whole I need to use different code to read specific unique id base on data:.post.id from blogger post id itself. But i do not sure how to make it work. I am expecting when I know how to use different method which is making new code that find unique id for different article it would work fine.
You can just replace elem.text(data.value) to
// original count
var count = data.value;
// count separated by comma
var separatedCount = count.toString()
.split('').reverse().join('')
.match(/\d{1,3}/g).join(',')
.split('').reverse().join('');
elem.text(separatedCount);
The full code would be
<!-- code for views count -->
<script src='https://cdn.firebase.com/v0/firebase.js' type='text/javascript'/>
<script>
/*<![CDATA[*/
$.each($("a[name]"), function (i, e) {
var elem = $(e).parent().find("#postviews");
var blogStats = new Firebase("https://sh-v-3da10-default-rtdb.firebaseio.com/" + $(e).attr("name"));
blogStats.once("value", function (snapshot) {
var data = snapshot.val();
var isnew = false;
if (data == null) {
data = {};
data.value = 0;
data.url = window.location.href;
data.id = $(e).attr("name");
isnew = true;
}
// original count
var count = data.value;
// count separated by comma
var separatedCount = count.toString()
.split('').reverse().join('')
.match(/\d{1,3}/g).join(',')
.split('').reverse().join('');
elem.text(separatedCount);
data.value++;
if (window.location.pathname !== "/") {
if (isnew) blogStats.set(data); else blogStats.child("value").set(data.value);
}
});
});
/*]]>*/
</script>

Get second, third and so on values

I have this problem here
The problem has been solved, but my question is how can I get the second value from that, or the third one. The sheet will have many tables and at some point I will need a total for each table. Also, is there any solution to automatically find the the array number which contain date row for each table (instead defining this manually). Hope my explanation make sense.
Thank you!
Kind regards,
L.E. Test file
If I understood your question correctly, instead of breaking the loop when a match to "Total" is found do whatever is needed to be done within the loop like so...
var today = toDateFormat(new Date());
var todaysColumn =
values[5].map(toDateFormat).map(Number).indexOf(+today);
var emailDate = Utilities.formatDate(new Date(today),"GMT+1",
"dd/MM/yyyy");
for (var i=0; i<values.length; i++){
if (values[i][0]=='Total'){
nr = i;
Logger.log(nr);
var output = values[nr][todaysColumn];
// Do something with the output here I"m assuming you email it
}
}
The loop will keep going and find every "Total" and do the same thing. This answer assumes that the "Totals" are in the same column. You can get fancier with this if you only want certain tables to send and not others, but this should get you started.
I didn't quite understand the second part of your question...
"Also, is there any solution to automatically find the the array
number which contain date row for each table (instead defining this
manually). Hope my explanation make sense."
I'm guessing you want all the rows that contain "Total" in the specific column. You could instantiate a variable as an empty array like so, var totals = [];. Then instead of sending the email or whatever in the first loop you would push the row values to the array like so, totals.push(nr+1) . //adding 1 gives you the actual row number (rows count from 1 but arrays count from 0). You could then simply loop through the totals array and do whatever you wanted to do. Alternatively you could create an array of all the values instead of row numbers like totals.push(values[nr][todaysColumn]) and loop through that array. Lots of ways to solve this problem!
Ok based on our conversation below I've edited the "test" sheet and updated the code. Below are my edits
All edits have been made in your test sheet and verified working in Logger. Let me know if you have any questions.
Spreadsheet:
Added "Validation" Tab
Edited "Table" tab so the row with "Email Address" in Column A lines up with the desired lookup values (dates or categories)...this was only for the first two tables as all the others already had this criteria.
Code:
Create table/category selector...
In the editor go to File >> New >> HTMLfile
Name the file "inputHTML"
Copy and paste the following code into that file
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<form class="notice_form" autocomplete="off" onsubmit="formSubmit(this)" target="hidden_iframe">
<select id="tables" onchange="hideunhideCatagory(this.value)" required></select>
<p></p>
<select id="categories" style="display:none"></select>
<hr/>
<button class="submit" type="submit">Get Total</button>
</form>
<script>
window.addEventListener('load', function() {
console.log('Page is loaded');
});
</script>
<script
src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type="text/javascript">
// The code in this function runs when the page is loaded.
$(function() {
var tableRunner = google.script.run.withSuccessHandler(buildTableList);
var catagoryRunner = google.script.run.withSuccessHandler(buildCatagoryList);
tableRunner.getTables();
catagoryRunner.getCategories();
});
function buildTableList(tables) {
var list = $('#tables');
list.empty();
list.append('<option></option>');
for (var i = 0; i < tables.length; i++) {
if(tables[i]==''){break;}
list.append('<option>' + tables[i] + '</option>');
}
}
function buildCatagoryList(categories) {
var list = $('#categories');
list.empty();
list.append('<option></option>');
for (var i = 0; i < categories.length; i++) {
if(categories[i]==''){break;}
list.append('<option>' + categories[i] + '</option>');
}
}
function hideunhideCatagory(tableValue){
var catElem = document.getElementById("categories");
if(tableValue == "Total Calls By Date" || tableValue == "Total Appointments by Date"){
catElem.style.display = "none"
document.required = false;
}else{
catElem.style.display = "block"
document.required = true;
}
}
function formSubmit(argTheFormElement) {
var table = $("select[id=tables]").val(),
catagory = $("select[id=categories]").val();
console.log(table)
google.script.run
.withSuccessHandler(google.script.host.close)
.getTotal(table,catagory);
}
</script>
</body>
<div id="hiframe" style="display:block; visibility:hidden; float:right">
<iframe name="hidden_iframe" height="0px" width="0px" ></iframe>
</div>
</html>
Edits to Code.gs file
Replace code in Code.gs with this...
//This is a simple trigger that creates the menu item in your sheet
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Run Scripts Manually')
.addItem('Get Total','fncOpenMyDialog')
.addToUi();
}
//This function launches the dialog and is launched by the menu item
function fncOpenMyDialog() {
//Open a dialog
var htmlDlg = HtmlService.createHtmlOutputFromFile('inputHTML')
.setSandboxMode(HtmlService.SandboxMode.IFRAME)
.setWidth(200)
.setHeight(150);
SpreadsheetApp.getUi()
.showModalDialog(htmlDlg, 'Select table to get total for');
};
//main function called by clicking "Get Total" on the dialogue...variables are passed to this function from the formSubmit in the inputHTML javascript
function getTotal(table,catagory) {
function toDateFormat(date) {
try {return date.setHours(0,0,0,0);}
catch(e) {return;}
}
//get all values
var values = SpreadsheetApp
.openById("10pB0jDPG8HYolECQ3eg1lrOFjXQ6JRFwQ-llvdE2yuM")
.getSheetByName("Tables")
.getDataRange()
.getValues();
//declare/instantiate your variables
var tableHeaderRow, totalRow, tableFound = false;
//begin loop through column A in Tables Sheet
for (var i = 0; i<values.length; i++){
//test to see if values have already been found if so break the loop
if(tableFound == true){break;}
//check to see if value matches selected table
if (values[i][0]==table){
//start another loop immediately after the match row
for(var x=i+1; x<values.length; x++){
if(values[x][0] == "Email Address"){ //This header needs to consistantly denote the row that contains the headers
tableHeaderRow = x;
tableFound = true;
}else if(values[x][0] == "Total"){
totalRow = x;
break;
}
}
}
}
Logger.log("Header Row = "+tableHeaderRow)
Logger.log("Total Row = "+ totalRow)
var today = toDateFormat(new Date())
var columnToTotal;
if(catagory==''){
columnToTotal = values[tableHeaderRow].map(toDateFormat).map(Number).indexOf(+today);
}else{
columnToTotal = values[tableHeaderRow].indexOf(catagory);
}
var output = values[totalRow][columnToTotal];
Logger.log(output);
var emailDate = Utilities.formatDate(new Date(today),"GMT+1", "dd/MM/yyyy");
//here is where you would put your code to do something with the output
}
/** The functions below are used by the form to populate the selects **/
function getTables(){
var cFile = SpreadsheetApp.getActive();
var cSheet = cFile.getSheetByName('Validation');
var cSheetHeader = cSheet.getRange(1,1,cSheet.getLastRow(),cSheet.getLastColumn()).getValues().shift();
var tabelCol = (cSheetHeader.indexOf("Tables")+1);
var tables = cSheet.getRange(2,tabelCol,cSheet.getLastRow(),1).getValues();
return tables.filter(function (elem){
return elem != "";
});
}
function getCatagories(){
var cFile = SpreadsheetApp.getActive();
var cSheet = cFile.getSheetByName('Validation');
var cSheetHeader = cSheet.getRange(1,1,cSheet.getLastRow(),cSheet.getLastColumn()).getValues().shift();
var catagoriesCol = (cSheetHeader.indexOf("Catagory")+1);
var catagories = cSheet.getRange(2,catagoriesCol,cSheet.getLastRow(),1).getValues();
return catagories.filter(function (elem){
return elem != "";
});
}

Using Google Apps Script to make Google Forms that have scripts already attached

I am looking for a solution to a novel problem I have encountered in applying google apps scripting to, specifically, the google form product.
Context
The company I work for currently performs Quality Assurance(QA) on software we create for our clients by sending feedback through email.
This software is composed of "Parents" and their "Children". I was asked to look into using Google Forms as a method of creating QA feedback for each piece of software created.
I was able to get very far along in this process leveraging the Google Apps Script documentation. However, I have hit a knowledge barrier when it comes to implementing this in the wild.
Problem
I have one script attached to a very basic form that asks for the Name of the Tool(how we track our QA requests), Name of the Parents, and the name of the children for this software. (Currently I am asking for email as well for ease, but will soon replace with the automatic email grabbing function google apps script has).
This script takes in the responses to this first form and creates a new one using the responses. Now, for building purposes, I have created a second google apps script in the script editor of a form that was created by a submission of the first form. This script takes in the responses of to this second form and creates a third (I know, "formception" right?).
After building all this out and being fairly satisfied with my results I realized a massive error in my thinking. Outside of testing purposes users will be making many new forms from that first one. Each of these new forms will not have the google apps script, that I created for the second form, associated with them and as such will not generate the needed third form.
I am know seeking help identifying a method that will let the code I have written for the second form be automatically added to each new form the first creates. If this is not possible, I am seeking any alternatives. I have considered methods of containing the second google apps script within the first's codebase but I could not find a way to trigger that function on submission of the second form from within the first's script. Any ideas or approaches to consider would be very much appreciated.
Code:
As a note; I do realize this code is a bit messy and very redundant. This was hacked together as a brief proof of concept. I plan to clean it up and modularize it if I can find a solution to the issue above. Before wasting time on that though, I want to determine if what I am trying to do is possible within the limits of Google Apps Script.
First Script
//A function to run this unweildy Formception beast
//Its set to be run on a submission event of the original "First QA Form" which resides in ********'s Drive -> QA -> Dynamic Google Form Project Folder
function onSubmit() {
var form = FormApp.getActiveForm();
var formResponses = form.getResponses();
//this whole loop just puts the responses into nested arrays
for (var i = 0; i < formResponses.length; i++) {
var formResponse = formResponses[i];
var itemResponses = formResponse.getItemResponses();
for (var j = 0; j < itemResponses.length; j++) {
var itemResponse = itemResponses[j];
Logger.log('Response #%s to the question "%s" was "%s"',
(i + 1).toString(),
itemResponse.getItem().getTitle(),
itemResponse.getResponse());
}
}
//here we make another Form
var nextForm = FormApp.create('itemResponses[0].getResponse()');
//here we make a section for the questions that apply to the Tool as a whole
var generalSection = nextForm.addSectionHeaderItem();
generalSection.setTitle(itemResponses[0].getResponse());
//here we give the general section a checkbox item
var checkbox = nextForm.addCheckboxItem();
checkbox.setTitle('Which platforms did you test?');
checkbox.setChoices([
checkbox.createChoice('Chrome'),
checkbox.createChoice('FF'),
checkbox.createChoice('Safari'),
checkbox.createChoice('Vivaldi (Jokes)')
])
checkbox.setRequired(true);
//here we give the general section a multiple choice question and make it required
var generalLooks = nextForm.addMultipleChoiceItem()
.setTitle('Does this campaign look good in general?')
.setChoiceValues(['Yes','No'])
.setRequired(true);
//here we give the general section a place for comments
var generalComment = nextForm.addParagraphTextItem()
.setTitle('General comments:')
.setHelpText('Separate each comment with a return.')
.setRequired(false);
//here we give the general section a place for images to be submitted
var generalImg = nextForm.addParagraphTextItem()
.setTitle('General comment reference image links:')
.setHelpText('Separate each image link with a return.')
.setRequired(false);
//here we create a new section to conatin all the parents
var parentPage = nextForm.addPageBreakItem();
parentPage.setTitle(itemResponses[0].getResponse() + '| Parent(s)');
//here we create an array to conatain all the parent names
var parents = [{}];
//we populate this array with the responses to the second question of the "First QA Form" which asked for ther Parent names seperated by returns
parents = itemResponses[1].getResponse().split("\n");
//this for loop creates a section and series of questions related to each parent
for (var p = 0; p < parents.length; p++) {
//adds a section for each parent
var parentSection = nextForm.addSectionHeaderItem().setTitle(parents[p]);
//adds a yes or no question for each parent
var parentLooks = nextForm.addMultipleChoiceItem()
//sets the name of the question dynamically using the current parent
.setTitle('Does ' + parents[p] + ' look good in general?')
.setChoiceValues(['Yes','No'])
.setRequired(true);
//adds a comment section for each
var parentComment = nextForm.addParagraphTextItem()
.setTitle(parents[p] + ' comments:')
.setHelpText('Separate each comment with a return.')
.setRequired(false);
//adds an img section for each (there is potential to get into regex here and verify links)(there is also potential to replace with apps script UI stuff for direct upload)
var parentImg = nextForm.addParagraphTextItem()
.setTitle(parents[p] + ' image links:')
.setHelpText('Separate each image link with a return.')
.setRequired(false);
}
//end for loop
//makes a new page for the children
var childPage = nextForm.addPageBreakItem();
childPage.setTitle(itemResponses[0].getResponse() + '| Children');
var children = [{}];
children = itemResponses[2].getResponse().split("\n");
//this for loop creates a section and series of questions related to each child
for (var c = 0; c < children.length; c++) {
var childSection = nextForm.addSectionHeaderItem().setTitle(children[c]);
var parentSelect = nextForm.addListItem().setRequired(true);
parentSelect.setTitle('Which parent does this child belong to?');
parentSelect.setChoiceValues(parents);
//adds a yes or no question for each parent
var childrenLooks = nextForm.addMultipleChoiceItem()
.setTitle('Does ' + children[c] + ' look good in general?')
.setChoiceValues(['Yes','No'])
.setRequired(true);
//adds a comment section for each
var childrenComment = nextForm.addParagraphTextItem()
.setTitle(children[c] + ' comments:')
.setHelpText('Separate each comment with a return.')
.setRequired(false);
//adds an img section for each (there is potential to get into regex here and verify links)(there is also potential to replace with apps script UI stuff for direct upload)
var childImg = nextForm.addParagraphTextItem()
.setTitle(children[c] + ' image links:')
.setHelpText('Separate each image link with a return.')
.setRequired(false);
}
//end for loop
//we need the email of the account manager we want this to go to after we fill it out
var finalStep = nextForm.addSectionHeaderItem();
finalStep.setTitle('Final Step');
//this is a response field that grabs the email of the account manager, it is required.
var accountEmail = nextForm.addTextItem();
accountEmail.setTitle('What is the email of this account manager?').setRequired(true);
//grabs the form we just made's ID
var id = nextForm.getId();
//create the link that will be sent to the QAer to respond with content and images
var emailBody = 'https://docs.google.com/a/***********.com/forms/d/' + id + '/viewform';
//set the email of the QAer
var email = itemResponses[3].getResponse();
//set the subject of the email to the name of the Tool
var emailSubject = itemResponses[0].getResponse();
//send the email of the link to the new form to the QAer
MailApp.sendEmail({
to: email,
subject: emailSubject,
htmlBody: emailBody});
Second Form Script
//set to be run on a submission event of the second form "Next QA Form" which resides in ********'s Drive
function onLastSubmit() {
var form = FormApp.getActiveForm();
var formResponses = form.getResponses();
//loop just puts the current responses into nested arrays
for (var i = 0; i < formResponses.length; i++) {
var formResponse = formResponses[i];
var itemResponses = formResponse.getItemResponses();
for (var j = 0; j < itemResponses.length; j++) {
var itemResponse = itemResponses[j];
// Logger.log('Response #%s to the question "%s" was "%s"',
// (i + 1).toString(),
// itemResponse.getItem().getTitle(),
// itemResponse.getResponse());
}
}
//create a Form instance of our last(old) form. It will be usefull in accessing data like parent and child names
var previousForm = FormApp.openById('***********************');
var oldFormResponses = previousForm.getResponses();
//loop just puts the old responses into nested arrays
for (var i = 0; i < oldFormResponses.length; i++) {
var oldFormResponse = oldFormResponses[i];
var oldItemResponses = oldFormResponse.getItemResponses();
for (var j = 0; j < oldItemResponses.length; j++) {
var oldItemResponse = oldItemResponses[j];
// Logger.log('Response #%s to the question "%s" was "%s"',
// (i + 1).toString(),
// oldItemResponse.getItem().getTitle(),
// oldItemResponse.getResponse());
}
}
//some debugging and such
Logger.log(oldItemResponses[0].getResponse());
Logger.log(itemResponses[4].getResponse());
//oldItemResponses[0] = Name of Tool
var toolName = oldItemResponses[0].getResponse();
Logger.log(toolName);
//oldItemResponses[1] = parent names
var parentNames = oldItemResponses[1].getResponse();
Logger.log(parentNames);
//oldItemResponses[2] = child names
var childNames = oldItemResponses[2].getResponse();
Logger.log(childNames);
//oldItemResponses[3] = email of the QAer
var qaEmail = oldItemResponses[3].getResponse();
//newItemResponse[0] = tested platforms
var testedPlatforms = itemResponses[0].getResponse();
//make the last form
var lastForm = FormApp.create('Account Manager Response | ' + toolName);
//make a section for the general content
var generalSection = lastForm.addSectionHeaderItem();
generalSection.setTitle(toolName + ' | General Section');
//make a checkbox item for the CD to approve each of the platforms that the QAer says were tested
var testedCheckbox = lastForm.addCheckboxItem();
testedCheckbox.setTitle('If you agree a platform was accurately tested please check it off below.');
//use the array from the first response of the previous form (platforms that were tested) to generate a list of the tested platforms for the CD to approve
if ( Array.isArray(testedPlatforms)) {
testedCheckbox.setChoiceValues(testedPlatforms);
} else {
testedCheckbox.createChoice(testedPlatforms);
}
//set general section response variables
var genYesNo = itemResponses[1].getResponse();
var genComments = itemResponses[2].getResponse();
var genImgs = itemResponses[3].getResponse();
//if statement either says the general section looks good or makes a bunch of fields with the content the QAer left
if ( genYesNo == 'Yes') {
generalSection.setHelpText('Looks Good!')
} else {
//make a checkbox item for the CD to approve or not approve the general section QA feedback
if ( genComments != '') {
var generalCheckbox = lastForm.addCheckboxItem();
generalCheckbox.setTitle(toolName + ' | General Information and Comments');
generalCheckbox.setHelpText('Please check the boxes that you have fixed. Feel free to leave a note about any in the following section.');
if ( Array.isArray(genComments)) {
generalCheckbox.setChoiceValues(genComments);
} else {
generalCheckbox.createChoice(genComments);
}
}
//create a for loop to display image items for any linked images that were included by the QAer in the general section
if ( genImgs != '') {
if ( Array.isArray(genImgs)){
for (var gI = 0; gI < genImgs.length; gI++) {
var generalImg = lastForm.addImageItem();
generalImg.setTitle('General Section | Image ' + (gI + 1));
var genImg = UrlFetchApp.fetch(genImgs[gI]);
generalImg.setImage(genImg);
}
} else {
var generalImg = lastForm.addImageItem();
generalImg.setTitle('General Section | Image 1');
var genImg = UrlFetchApp.fetch(genImgs);
generalImg.setImage(genImg);
}
}
}
//make a paragraphTextItem for the CD to leave notes about this section if they would like
var generalNotes = lastForm.addParagraphTextItem()
.setTitle('Notes about the general section:')
.setHelpText('Leave notes here about any items you have not fixed and other things you would like the QAer to know.');
//make a new page for the parent content
var parentPage = lastForm.addPageBreakItem();
parentPage.setTitle(toolName + ' | Parent(s)');
//a variable that we can increment by 2 to account for there being 3 items in each parent
var incParent = 0;
//a loop that creates items for each parent including: new section, checkbox to approve content and image displays
for (var i = 0; i < parentNames.length; i++) {
var parYesNo = itemResponses[(i + incParent) + 5].getResponse();
var parComments = itemResponses[(i + incParent) + 5].getResponse();
var parImgs = itemResponses[(i + incParent) + 5].getResponse();
//create the new section for each parent
var parentSection = lastForm.addSectionHeaderItem();
//and name it
parentSection.setTitle(parentNames[i]);
//if statement to ensure we dont show any content if the QAer checked 'Yes' for looks good
//using incOne to ensure
if (parYesNo == 'Yes') {
parentSection.setHelpText('Looks Good!');
} else {
//create a checkbox list for all the comments the QAer listed if they clicked 'No' for looks good
if (parComments != '') {
var parentCheckbox = lastForm.addCheckboxItem();
parentCheckbox.setTitle(parentNames[i] + ' | QA Comments');
parentCheckbox.setHelpText('Please check the boxes that you have fixed. Feel free to leave a note about any in the following section.');
if (Array.isArray(parComments)) {
parentCheckbox.setChoiceValues(parComments);
} else {
parentCheckbox.createChoice(parComments)
}
}
}
//create the images the QAer listed if they clicked 'No' for looks good
if (parImgs != '') {
if (Array.isArray(parImgs)) {
for (var pI = 0; gI < parImgs.length; pI++) {
var parentImg = lastForm.addImageItem();
parentImg.setTitle(parentNames[i] + ' | Image ' + (pI + 1));
var parImg = UrlFetchApp.fetch(parImgs[pI]);
parentImg.setImage(parImg);
}
} else {
var parentImg = lastForm.addImageItem();
parentImg.setTitle(parentNames[i] + ' | Image ');
var parImg = UrlFetchApp.fetch(parImgs[pI]);
parentImg.setImage(parImg)
}
}
//increment to account for the other items in each parent
incParent += 2;
}
//end for loop
//make a new page for the children content
var childPage = lastForm.addPageBreakItem();
childPage.setTitle(toolName + ' | Children');
//determine how many parents there are and count three items for each
//also account for the items from the general section (4 items)
var parentItems = parentNames.length * 3;
var nonChildItems = parentItems + 4;
//a variable that we can increment by 4(the number of items in each child)
var incChild = 0;
//creates items for each parent including: checkbox to approve content and image displays
for (var j = 0; j < childNames.length; j++) {
var chiYesNo = itemResponses[nonChildItems + (j + incChild)].getResponse();
var chiComments = itemResponses[(j + incChild) + nonChildItems].getResponse();
var chiImgs = itemResponses[(j + incChild) + nonChildItems].getResponse();
//create sections for each child
var childSection = lastForm.addSectionHeaderItem();
childSection.setTitle(childNames[j] + ' | ' + itemResponses[nonChildItems + (j + incChild + 1)].getResponse());
if (chiYesNo == 'Yes') {
childSection.setHelpText('Looks Good!');
} else {
//create a checkbox list for all the comments the QAer listed if they clicked 'No' for looks good
if (chiComments != '') {
var childCheckbox = lastForm.addCheckboxItem();
childCheckbox.setTitle(childNames[j] + ' | QA Comments');
childCheckbox.setHelpText('Please check the boxes that you have fixed. Feel free to leave a note about any in the following section.');
if (Array.isArray(chiComments)) {
childCheckbox.setChoiceValues(chiComments);
} else {
childCheckbox.createChoice(chiComments);
}
}
}
//create the images the QAer listed if they clicked 'No' for looks good
if (chiImgs != '') {
if (Array.isArray(chiImgs)) {
for (var cI = 0; cI < chiImgs.length; cI++) {
var childImg = lastForm.addImageItem();
childImg.setTitle(childNames[j] + ' | Image ' + (cI + 1));
var chiImg = UrlFetchApp.fetch(chiImgs[cI]);
childImg.setImage(chiImg);
}
} else {
var childImg = lastForm.addImageItem();
childImg.setTitle(childNames[j] + ' | Image ');
var chiImg = UrlFetchApp.fetch(chiImgs[cI]);
childImg.setImage(chiImg);
}
}
//increment to account for the other items in each child
incChild += 3;
}
//end for loop
//grabs the form we just made's ID
var id = lastForm.getId();
//create the link that will be sent to the QAer to respond with content and images
var emailBody = 'https://docs.google.com/a/**************.com/forms/d/' + id + '/viewform';
//set the email of the QAer
var email = qaEmail;
//set the subject of the email to the name of the Tool
var emailSubject = toolName + ' | CD Response';
//send the email of the link to the new form to the CD
MailApp.sendEmail({
to: email,
subject: emailSubject,
htmlBody: emailBody});
}
Thanks in advance!
*edit for company privacy reasons.
I've been doing something very similar and have mostly been successful.
I was able to ensure code is moved over to newly created forms by creating a blank template form, with the necessary script attached.
When when a new form is needed with this script, I create a copy of the template document and then populate this with the necessary contents.
The only problem I have run into with this is being unable to easily set up triggers for code to run on form submission in these new forms. I have solved this by prompting the user to open the newly created form and click on a menu item I have added to 'initialise permissions'.
Unfortunately there is no way to programmatically attach a script to a form. In general, if you expect a script to be used on multiple forms, docs, etc, it's best to convert it to an add-on. This has the benefit of allowing you to make updates to the script over time, instead of each being a local copy.
Forms making forms making forms is also probably an anti-pattern. What you probably need is a more complex web app, which you can build in Apps Script but is quite a bit more involved.

Hover over data using title attribute in javascript

I have a javascript code that displays data in a table format and when hovered over the first column it displays additional details. The hover over code is using jquery tooltip and the title attribute of html. The code works fine in most cases but if one of the fields I am displaying in the hover has " symbol it screws up everything that record onwards and the hover and main data display together and the hover doesnt work on those rows.
below is a snapshot of my code
var medicationName = medJSON.MED_DETAILS[medIdx1].ORDER_NAME;
var orderdetails = medJSON.MED_DETAILS[medIdx1].ORD_DETAILS;
var comments = medJSON.MED_DETAILS[medIdx1].ORD_COMMENTS;
var reqStart = medJSON.MED_DETAILS[medIdx1].REQ_ST_DT;
var originalStart = medJSON.MED_DETAILS[medIdx1].ORIG_ORD_DT;
var lastDose = medJSON.MED_DETAILS[medIdx1].LAST_DOSE;
var nextDose = medJSON.MED_DETAILS[medIdx1].NEXT_DOSE;
var stopDt = medJSON.MED_DETAILS[medIdx1].STOP_DT_TM;
var stopReason = medJSON.MED_DETAILS[medIdx1].STOP_REASON;
var enteredBy = medJSON.MED_DETAILS[medIdx1].ORDER_ENTERED_BY;
var status = medJSON.MED_DETAILS[medIdx1].ORD_STATUS;
var simpleDetails = medJSON.MED_DETAILS[medIdx1].CLIN_DISP_LN;
if(nextDose.length == 0)
{
nextDose = "Not Defined";
}
var medHover = ["<table><tr><td><b>Medication:</b></td><td>",medicationName,"</td></tr>"
,"<tr><td><b>Details:</b></td><td>",simpleDetails,"</td></tr>"
//,"<tr><td><b>Order Comments:</b></td><td>",comments,"</td></tr>"
,"<tr><td><b>Request Start:</b></td><td>",reqStart,"</td></tr>"
,"<tr><td width = 200px><b>Original Order Date/Time:</b></td><td>",originalStart,"</td></tr>"
,"<tr><td><b>Last Documented Dose:</b></td><td>",lastDose,"</td></tr>"
,"<tr><td><b>Next Scheduled Dose:</b></td><td>",nextDose,"</td></tr>"
,"<tr><td><b>Stop Date/Time:</b></td><td>",stopDt,"</td></tr>"
,"<tr><td><b>Stop Reason:</b></td><td>",stopReason,"</td></tr>"
,"<tr><td><b>Order Entered By:</b></td><td>",enteredBy,"</td></tr>"
,"<tr><td><b>Status:</b></td><td>",status,"</td></tr>"
,"</table>"]
tempStr1.push("<tr class = 'evenrow' ><td class = 'cmedname custhvr' title=\"",medHover.join(""),"\">",medicationName,"</td><td> ",simpleDetails,"</td></tr>")
thanks,
Sid
Process medHover with:
medHover.join("").replace('\"', '"');
This replaces the quote character with a value usable with HTML.

Missing value on JSON file

The code is created as follow:
function create_story_json_file()
{
//Update the last edited page:
img_dataURLs[current_page]= drawing_plate.toDataURL("image/png");
create_display_img_url(current_page);
var page_num= total_page_num; //Story total page number
var page_cont= new Array();
var page_view= new Array();
//Page View:( as the pages is clicked, the page views have to be shown.
page_view= display_img_dataURL;
var img_data_URL; //if it's a variable only, you have to assign the first value in the declaration, or the tag would disappear.
var stamp_arr= new Array();
var rec_arr= new Array();
var background_msc;
//For each Story:
alert("total_page_num :"+ total_page_num );
for(var p_number=0 ; p_number < total_page_num ; p_number++)
{
img_data_URL= img_dataURLs[p_number];
//Stamp
stamp_arr= []; //reset.
var stamp_arr_for_current_page= stamp_for_all_pages[ p_number ].arr;
for(var stamp_num= 0; stamp_num < stamp_arr_for_current_page.length ; stamp_num++)
{
stamp_arr.push( stamp_arr_for_current_page[stamp_num].get_stmp_json_obj );
}
alert("stamp_arr.length is:" + stamp_arr.length);
//Rec:
rec_arr= [];
var rec_objs_at_certain_page= records_pages_arr[ p_number ].rec_objs;
for(var rec_num= 0; rec_num < rec_objs_at_certain_page.length; rec_num++)
{
rec_arr.push( rec_objs_at_certain_page[ rec_num ].get_rec_json_obj ); //check if rec_objs_at_certain_page[ rec_num ] is a rec_object!
}
alert("rec_arr length is: " + rec_arr.length);
//Background_music:
var bgr_msc_in_certain_page= back_ground_music_arr[ p_number ];
alert ("bgr_msc_in_certain_page.created" + bgr_msc_in_certain_page.created);
background_msc= bgr_msc_in_certain_page.get_bgr_msc_json_obj;
var page_content_json_obj= {
img_data_url: img_data_URL,
stamp:stamp_arr,
record: rec_arr,
bgr_msc: background_msc
}
page_cont.push(page_content_json_obj);
}
var story_json_obj= {
page_number: page_num,
page_content: page_cont,
page_img_view: page_view
}
//Change to JSON String and write it to the file.
story_json_str= JSON.stringify(story_json_obj);
}
I am confused about that why the result JSON string: story_json_str would be:
{"page_number":1,
"page_content":[{"img_data_url":"data:image/base64......lots of character"}]}
And nothing else, where are "stamp" ,"record" and "bgr_msc" in "page_content"?
And why does "page_img_view" disappear too?
Why do they miss?
Please explain and correct the code.
Ps: I work on Android System, storing the JSON string to a file by the feature of HTML5. I don't have debug platform to use...
I found the fault eventually.
background_msc= bgr_msc_in_certain_page.get_bgr_msc_json_obj;
Since get_bgr_msc_json_obj is a function in a class, I need to write
get_bgr_msc_json_obj(). Missing the parentheses won't call the function.
These two instruments: get_rec_json_obj and get_stmp_json_obj make the same mistake. What a stupid mistake.

Categories

Resources