0

I’m trying figure out something that has led me to the point of not even seeing the wood through the trees. I’m a noob when it comes to JavaScript and I would normally use a database to sort this but don’t have that option here.

What I'm actually working on is:

This is a quiz application that asks users to respond to a (descrete answer/SCORM Compliant) question, then another (Free text/Long Text) question. This particular part of the code is used to create the PDF output of the user's responses (with a little bit of header information).

I have to use JavaScript to build a pdf (using “jsPDF - Parallax” ) that outputs a set of variables that I’ve generated else where. E.g.

//VARIABLES........................................................................

var NoofQuesAnswered = VarNoofQuesAnswered.getValue();
var User_Score = VarUser_Score.getValue();
var CorrectImagData = 'data:image/jpeg;base64,/9j/etc/etc'; //Omitted actual 64base text
var IncorrectImgData = 'data:image/jpeg;base64,/9j/etc/etc'; //Omitted actual 64base text

/* General Text Values */
var notAnswered = '~~~null~~~';
var questionExcludedTitle = 'Question Excluded';
var questionAnswerGivenTitle = 'Answer Given';
var openQuestionTitle = 'Open Question';

/* Question Title - Variables */
var questionTitle_1 = 'Question 1';
var questionTitle_2 = 'Question 2';
var questionTitle_3 = 'Question 3';
var questionTitle_4 = 'Question 4';
var questionTitle_5 = 'Question 5';
var questionTitle_N = 'Question N';

/* Question Response/Answer Given - Variables */

//These variables are determined elsewhere (XML/Javascript)
var UsersAnswer_Que1 = Var_UsersAnswer_Que1.getValue(); 
var UsersAnswer_Que2 = Var_UsersAnswer_Que2.getValue();
var UsersAnswer_Que3 = Var_UsersAnswer_Que3.getValue();
var UsersAnswer_Que4 = Var_UsersAnswer_Que4.getValue();
var UsersAnswer_Que5 = Var_UsersAnswer_Que5.getValue();
var UsersAnswer_QueN = Var_UsersAnswer_QueN.getValue();

/* Open Question - Variables */

var openQuestion_1 = 'Why are young people potentially at risk?';
var openQuestion_2 = 'Why are there champions for young people?';
var openQuestion_3 = 'How does social media impact on the lives of young people?';
var openQuestion_4 = 'What kinds of support are there for young people, in your area?';
var openQuestion_5 = 'What type of information are young people most likely to need in crisis?';
var openQuestion_N = 'Open question (n)';

/* Open Question - User Response/Answer Given Variables */

//These variables are determined elsewhere (XML/Javascript)
var UserResp_LongTextQue_1 = Var_UserResp_LongTextQue_1.getValue();
var UserResp_LongTextQue_2 = Var_UserResp_LongTextQue_2.getValue();
var UserResp_LongTextQue_3 = Var_UserResp_LongTextQue_3.getValue();
var UserResp_LongTextQue_4 = Var_UserResp_LongTextQue_4.getValue();
var UserResp_LongTextQue_5 = Var_UserResp_LongTextQue_5.getValue();
var UserResp_LongTextQue_N = Var_UserResp_LongTextQue_N.getValue();

Then by using jsPDF I am building the page like this, to setup the header information on the first page (which is the only page that has different content on it:

function genPDF() { //Function to output the pdf using jsPDF

  var doc = new jsPDF();

  /* Begin Page Build */

  // Page Header Space........................................................................

  /* There are some other logos and other header bits here but I have ommitted them due to copyright */

  doc.setFont('helvetica')

  doc.setFontSize(30)
  doc.text(50, 55, 'Results and Responses')

  doc.setFontSize(14)
  doc.text(45, 78, 'No. of Questions Answered -')
  doc.text(113, 78, NoofQuesAnswered)

  doc.text(125, 78, 'Final score -')
  doc.text(158, 78, User_Score)

  doc.line(20, 82, 195, 82)

  // Questions with responses

  /* This is the point at which i need to build the page dynamically becasue the stuff above is all static and everything below could be built dynically */

  // Question_1

  doc.line(20, 113, 195, 113)

  if (Var_UsersAnswer_Que1.equals(notAnswered)) {
    doc.setFontSize(25)
    doc.text(65, 125, questionTitle_1)
    doc.line(20, 130, 195, 130)
    doc.setFontSize(30)
    doc.text(58, 155, questionExcludedTitle)
  } else {
    doc.setFontSize(14)
    doc.text(20, 120, questionAnswerGivenTitle)
    doc.setFontSize(12)
    var splitUsersAnswer_Que1 = doc.splitTextToSize(usersAnswer_Que1, 150);
    doc.text(20, 127, splitUsersAnswer_Que1)

    doc.line(20, 130, 195, 130)

    doc.setFontSize(14)
    doc.text(20, 137, openQuestionTitle)

    doc.setFontSize(12)
    var splitOpenQuestion_1 = doc.splitTextToSize(openQuestion_1, 180);
    doc.text(20, 145, splitOpenQuestion_1)

    if (Var_UsersAnswer_Que1.isCorr('\u0041\u006C\u006C\u0020\u0061\u0072\u0065')) {
      doc.addImage(CorrectImagData, 'Correct Image', 185, 115, 10, 11)
    } else {
      doc.addImage(IncorrectImgData, 'Incorrect Image', 185, 115, 10, 11)
    }

    doc.setFontSize(12)
    var splitUserResp_LongTextQue_1 = doc.splitTextToSize(userResp_LongTextQue_1, 170);
    doc.text(20, 160, splitUserResp_LongTextQue_1)
    doc.line(20, 153, 195, 153)
  }

  // Question_2

  doc.line(20, 190, 195, 190)

  if (Var_UsersAnswer_Que2.equals(notAnswered)) {
    doc.setFontSize(25)
    doc.text(65, 202, questionTitle_2)
    doc.line(20, 207, 195, 207)
    doc.setFontSize(30)
    doc.text(58, 232, questionExcludedTitle)
  } else {
    doc.setFontSize(14)
    doc.text(20, 197, questionAnswerGivenTitle)
    doc.setFontSize(12)
    var splitUsersAnswer_Que2 = doc.splitTextToSize(usersAnswer_Que2, 150);
    doc.text(20, 204, splitUsersAnswer_Que2)

    doc.line(20, 207, 195, 207)

    doc.setFontSize(14)
    doc.text(20, 214, openQuestionTitle)

    doc.setFontSize(12)
    var splitOpenQuestion_2 = doc.splitTextToSize(openQuestion_2, 180);
    doc.text(20, 222, splitOpenQuestion_2)

    if (Var_UsersAnswer_Que2.isCorr('\u0049\u006E\u0066\u006F\u0072\u006D\u0061\u0074\u0069\u006F\u006E')) {
      doc.addImage(CorrectImagData, 'Correct Image', 185, 192, 10, 11)
    } else {
      doc.addImage(IncorrectImgData, 'Incorrect Image', 185, 192, 10, 11)
    }

    doc.setFontSize(12)
    var splitUserResp_LongTextQue_2 = doc.splitTextToSize(userResp_LongTextQue_2, 170);
    doc.text(20, 237, splitUserResp_LongTextQue_2)
    doc.line(20, 230, 195, 230)
  }

  //New Page - From here down, the position of everything on the page will be the same

  doc.addPage()

  // Question_3

  doc.line(20, 13, 195, 13)

  if (Var_UsersAnswer_Que3.equals(notAnswered)) {
    doc.setFontSize(25)
    doc.text(65, 25, questionTitle_3)
    doc.line(20, 30, 195, 30)
    doc.setFontSize(30)
    doc.text(58, 55, questionExcludedTitle)
  } else {
    doc.setFontSize(14)
    doc.text(20, 20, questionAnswerGivenTitle)
    doc.setFontSize(12)
    var splitUsersAnswer_Que3 = doc.splitTextToSize(usersAnswer_Que3, 150);
    doc.text(20, 27, splitUsersAnswer_Que3)

    doc.line(20, 30, 195, 30)

    doc.setFontSize(14)
    doc.text(20, 37, openQuestionTitle)

    doc.setFontSize(12)
    var splitOpenQuestion_3 = doc.splitTextToSize(openQuestion_3, 180);
    doc.text(20, 45, splitOpenQuestion_3)

    if (Var_UsersAnswer_Que3.isCorr('\u0041\u006C\u006C\u0020')) {
      doc.addImage(CorrectImagData, 'Correct Image', 185, 15, 10, 11)
    } else {
      doc.addImage(IncorrectImgData, 'Incorrect Image', 185, 15, 10, 11)
    }

    doc.setFontSize(12)
    var splitUserResp_LongTextQue_3 = doc.splitTextToSize(userResp_LongTextQue_3, 170);
    doc.text(20, 60, splitUserResp_LongTextQue_3)
    doc.line(20, 53, 195, 53)
  }

  // Question_4

  doc.line(20, 90, 195, 90)

  if (Var_UsersAnswer_Que4.equals(notAnswered)) {
    doc.setFontSize(25)
    doc.text(65, 102, questionTitle_4)
    doc.line(20, 107, 195, 107)
    doc.setFontSize(30)
    doc.text(58, 132, questionExcludedTitle)
  } else {
    doc.setFontSize(14)
    doc.text(20, 97, questionAnswerGivenTitle)
    doc.setFontSize(12)
    var splitUsersAnswer_Que4 = doc.splitTextToSize(usersAnswer_Que4, 150);
    doc.text(20, 104, splitUsersAnswer_Que4)

    doc.line(20, 107, 195, 107)

    doc.setFontSize(14)
    doc.text(20, 114, openQuestionTitle)

    doc.setFontSize(12)
    var splitOpenQuestion_4 = doc.splitTextToSize(openQuestion_4, 180);
    doc.text(20, 122, splitOpenQuestion_4)

    if (Var_UsersAnswer_Que4.isCorr('\u0041\u006C\u006C\u0020\u0061\u0072\u0065\u0020')) {
      doc.addImage(CorrectImagData, 'Correct Image', 185, 92, 10, 11)
    } else {
      doc.addImage(IncorrectImgData, 'Incorrect Image', 185, 92, 10, 11)
    }

    doc.setFontSize(12)
    var splitUserResp_LongTextQue_4 = doc.splitTextToSize(UserResp_LongTextQue_4, 170);
    doc.text(20, 137, splitUserResp_LongTextQue_4)
    doc.line(20, 130, 195, 130)
  }

  // Question_5

  doc.line(20, 167, 195, 167)

  if (Var_UsersAnswer_Que5.equals(notAnswered)) {
    doc.setFontSize(25)
    doc.text(65, 179, questionTitle_5)
    doc.line(20, 184, 195, 184)
    doc.setFontSize(30)
    doc.text(58, 209, questionExcludedTitle)
  } else {
    doc.setFontSize(14)
    doc.text(20, 174, questionAnswerGivenTitle)
    doc.setFontSize(12)
    var splitUsersAnswer_Que5 = doc.splitTextToSize(usersAnswer_Que5, 150);
    doc.text(20, 181, splitUsersAnswer_Que5)

    doc.line(20, 184, 195, 184)

    doc.setFontSize(14)
    doc.text(20, 191, openQuestionTitle)

    doc.setFontSize(12)
    var splitOpenQuestion_5 = doc.splitTextToSize(openQuestion_5, 180);
    doc.text(20, 199, splitOpenQuestion_5)

    if (Var_UsersAnswer_Que5.isCorr('\u0048\u006F\u0077\u0020\u0074\u006F\u0020\u0067\u0065\u0074')) {
      doc.addImage(CorrectImagData, 'Correct Image', 185, 169, 10, 11)
    } else {
      doc.addImage(IncorrectImgData, 'Incorrect Image', 185, 169, 10, 11)
    }

    doc.setFontSize(12)
    var splitUserResp_LongTextQue_5 = doc.splitTextToSize(openQuestion_5, 170);
    doc.text(20, 214, splitUserResp_LongTextQue_5)
    doc.line(20, 207, 195, 207)
  }

  //New Page - There are another 55 questions

  // doc.addPage()

  /* Question_N

  doc.line(20, 13, 195, 13)

  if (Var_UsersAnswer_QueN.equals(notAnswered)) {
   doc.setFontSize(25)
   doc.text(65, 25, questionTitle_N)
   doc.line(20, 30, 195, 30)
   doc.setFontSize(30)
   doc.text(58, 55, questionExcludedTitle)
  } else {
   doc.setFontSize(14)
   doc.text(20, 20, questionAnswerGivenTitle)
   doc.setFontSize(12)
   var splitUsersAnswer_QueN = doc.splitTextToSize(usersAnswer_QueN, 150);
   doc.text(20, 27, splitUsersAnswer_QueN)

   doc.line(20, 30, 195, 30)

   doc.setFontSize(14)
   doc.text(20, 37, openQuestionTitle)

   doc.setFontSize(12)
   var splitOpenQuestion_N = doc.splitTextToSize(openQuestion_N, 180);
   doc.text(20, 45, splitOpenQuestion_N)

   if (Var_UsersAnswer_QueN.isCorr('\u0041\u006C\u006C\u0020')) {
    doc.addImage(CorrectImagData, 'Correct Image', 185, 15, 10, 11)
   } else {
    doc.addImage(IncorrectImgData, 'Incorrect Image', 185, 15, 10, 11)
   }

   doc.setFontSize(12)
   var splitUserResp_LongTextQue_N = doc.splitTextToSize(userResp_LongTextQue_N, 170);
   doc.text(20, 60, splitUserResp_LongTextQue_N)
   doc.line(20, 53, 195, 53)
  }
 
  etc................................................
 
  */

  // Save document/Create PDF

  doc.save('Test.pdf');
}

At the moment, the result of this code is the production of a pdf with each question (1-60) with a predefined page position for each question and each element for that particular question. It will however, check to see if there is response given (users are only asked to answer 30 randomly determined questions throughout all of the 60 questions), and if there is no response to that question (because the application didn't even present that question to the user) it will say "Question Excluded" but will keep the space on the page.

As a result, I end up with 40+ pages, where only the answered questions display the user response, whist the questions that have been excluded are displayed as such.

I would love to be able to dynamically build the page using (I think) an array that is populated with the variables once it has established the questions that haven't been answered and then completely ignores them, before building the pdf with only the questions that the user has responded to.

What I am trying to achieve, is to reduce the number of pages based on the number of questions the user has answered (which could be 1 or 2 but might be as many as 30). The thing I can't get my head around is the fact that, because I have to state the actual position on the page for each element, I can't just get it to stack them automatically AND because I have to use Javascript I can't just Query the responses and then insert them into the page on the fly.

Any help would be greatly appreciated.

I might be going down completely the wrong track here so happy to hear a better approach.

Thanks in advance.

  • For the part where you're creating the array with the variables, could you post your code attempt (or something close to it)? – strider Nov 11 '17 at 18:15
  • I will post some more example code of what I’m trying to do tomorrow (it’s 7.50pm GMT) here, so I’ve left it for the evening but I will be getting back on it tomorrow afternoon. Cheers for the quick response guys. –  Nov 11 '17 at 18:52
  • Hey @bitstrider, I have updated the post to include the example code. Let me know if there is anything else you would like to see. I can attach an example of the output if you need it, as the code won't run because you wont be able to access the variables determined elsewhere in my application. Thanks! –  Nov 12 '17 at 13:57

1 Answers1

0

It sounds like you just want an array of responses, filtered for null:

const answers = [AnswerToQuestion1, AnswerToQuestion2, AnswerToQuestion3].filter(x => x);

the filter function it removing any records that are null or undefined. If your equivalent of a null answer isn't null, but is a string or something else, then you could filter it out like this:

const answers = [AnswerToQuestion1, AnswerToQuestion2, AnswerToQuestion3].filter(x => x != whateverYourNullLooksLike);
MorganIsBatman
  • 1,000
  • 8
  • 13
  • Thanks Morgan that sounds good. I’ll be trying it out tomorrow so I will let you know if it applies and if not I will give you some more info. –  Nov 11 '17 at 18:48
  • Hey @Morgan, I've updated my post to include the full code example. Do you think I would be able to use your idea of building an array and then filtering it for what I need to do? Would I need to use the filtered array to insert the elements into the placeholders positioned on the page (but only 30 placeholders). I hope I'm making sense here. Thanks again! –  Nov 12 '17 at 14:01
  • Your value for notAnswered looks to be the string '~~~null~~~', in which case you'll want to create your array like: – MorganIsBatman Nov 12 '17 at 18:11
  • Hey Morgan, Did you mean to include some code in your last comment? –  Nov 12 '17 at 22:22
  • Oops! I meant to say that if you want an array of answers that were answered, the second solution above would work, replacing 'whateverYourNullLooksLike' with '~~~null~~~'. – MorganIsBatman Nov 12 '17 at 22:41
  • I'm not sure how much you want to push your javascript knowledge for this, but I would approach this problem by building an array of objects, where each object contains the title, question, and answer for a single question. Depending on your datasource, it may be easier to build this array and omit unanswered questions as you go, or build the array of all questions then filter it in a similar manner to above. I'd then iterate through my array to dynamically place each question with a forEach loop, setting the rowHeight (and addPage) based on the array index of the question – MorganIsBatman Nov 12 '17 at 22:43
  • Hi Morgan, that’s great. I thought that this was the right line of thought and now I will spend my time building it like you have suggested. –  Nov 12 '17 at 23:08