Skip to content

[Developers] Survey Builder current state

zagorsky edited this page Apr 4, 2017 · 1 revision

Current state of the code

Jinja templates

All the templates are in the directory frontend/templates/.

  • edit_survey.html is the main template. It shows the questions in the survey. There are two survey types: audio_surveys and tracking_surveys. We're not changing anything about audio surveys; those surveys just have a "prompt" (something telling the respondent what to say). We're only concerned with tracking surveys; those are surveys with questions that you answer on a screen. The template edit_survey.html also includes three other templates:

    • survey_schedule.html: you can mostly ignore this. This is the box at the top of the screen that gives options about what times of the week the survey gets asked.

    • question_summary.html: This is written in Handlebars; it provides the text representation of a question in the main edit_survey.html page, and the four buttons attached to each question: Edit, Delete, Move Up, and Move Down. It should be rewritten in AngularJS.

    • randomize_questions.html: This shows some checkboxes at the bottom of the screen about whether to randomize the questions in a survey. We need two changes to this:

      1. Rewrite it to work in AngularJS instead of in Handlebars
      2. A survey can have either skip logic or randomized questions, but not both. This interface should reflect that. One way of doing this is to create an additional checkbox (somewhere in edit_survey.html) for whether the survey uses skip logic, and if that checkbox is checked, then disable the Randomize Questions checkboxes using <input disabled>.
  • edit_question.html is the template for the create/edit question popup/modal form.

JavaScript files

All the relevant JS files are in frontend/static/javascript/survey-editor/:

  • handlebars-question-rendering.js This file has helper functions for turning a question data object into a text representation of the question on the main survey page.

  • question-from-modal.js You edit questions in a modal/popup (there's no inline editing). questions-from-modal.js has functions to take the input from the modal form and turn that into a question data object.

  • radiobutton-checkbox-questions.js This file has functions for creating/editing radio button and checkbox questions in the modal/popup form. Radio button and checkbox questions are similar in that they have an arbitrary number of answers, so these functions are for increasing or decreasing the number of answer fields in the create/edit question modal. AngularJS could easily replace this functionality.

  • schedule.js You can probably ignore this file; it's all linked to the survey scheduling functionality in the survey_schedule.html template.

  • set-up-modal.js Most of this file is for parsing a question data object and populating the fields in the edit question modal form. This is functionality that would probably be much cleaner to write in AngularJS.

  • survey-editor.js This file has most of the functionality for the main survey editor page (i.e., not the edit question modal/popup). It has functions to add new questions, edit questions, re-order questions, and delete questions. It also has functions to read in an entire survey when you load the page, and to export the whole survey when you click "Save and Deploy." This file references functions defined in some of the other files (for example, lines 171-172 call functions clearModal() and populateEditQuestionModal() which are defined in set-up-modal.js); I think it's the only JS file in this directory that references other files, but I'm not totally sure.

Current JSON survey spec

A survey is represented as JSON and currently stored as a string in MongoDB. Its top-level attributes are:

  • _id: a randomly-generated, unique MongoDB ID

  • content: the list of questions. Each question has several attributes:

    • question_id: a randomly-generated ID (currently it's generated in JavaScript in question-from-modal.js's generateUUID() function
    • question_text: the text that appears with the question
    • question_type: allowed values are: free_response, checkbox, radio_button, slider, and info_text_box.
    • text_field_type (free_response questions only): allowed values are: NUMERIC, SINGLE_LINE_TEXT, and MULTI_LINE_TEXT
    • max and min (slider questions only): numbers that define the bottom and top of the slider's range
    • answers (radio_button and checkbox questions only): a list of answer options for a multiple-choice question
  • settings: currently, there are four attributes. None of these need to change to support skip logic, but we may need to add an additional setting that says survey skip logic is active, and which overrules the randomize attribute:

    • randomize: True or False; if True, the survey questions should appear in random order.
    • number_of_random_questions: this only matters if randomize == True. If it's None, then each survey the user takes should ask all the questions in the survey. If it's set to an integer, then each survey should ask only that many questions, drawn at random from the questions in this survey. For example, you could have a 30-question survey, but each time the survey gets asked, the user only sees a random 5 of those questions.
    • randomize_with_memory: True or False- if True, then the app remembers which questions were previously asked on a survey, and asks random questions without replacement, so it will go through the 30-question survey bank in 6 survey instances until it's asked all questions, and then start over.
    • trigger_on_first_download: True or False. If True, then as soon as the app downloads this survey for the first time (usually when the user installs and registers the app), the survey will appear. If False, the survey won't appear until its first explicitly scheduled time.
  • survey_type: this is set to tracking_survey for a survey with questions, or audio_survey for a survey with a "Record" button and a voice prompt. For this feature, we are only concerned with tracking surveys; you can ignore audio surveys.

  • timings: this is a list of the times during each week that the survey is supposed to be asked to the user. It's a list of 7 lists (one for each day of the week), and each day list is a list of integers, where each integer is the time, in seconds past midnight, that the survey is supposed to send. So for example, if you want to send a survey only once per week at 5pm on Mondays (5pm is (17 hours) * (3600 seconds/hour) = 61,200 seconds past midnight), your timings list-of-lists would look like this: [[], [61200], [], [], [], [], []]

Here is an example JSON representation of a survey:

{u'_id': ObjectId('55f34e5f73cc0a25217215ce'),
 u'content': [{u'question_id': u'5a0c14a3-7e7d-45df-ff71-7af4bff518e4',
   u'question_text': u'What do you most fear?',
   u'question_type': u'free_response',
   u'text_field_type': u'SINGLE_LINE_TEXT'},
  {u'answers': [{u'text': u'Cauliflower'},
    {u'text': u'Chia seeds'},
    {u'text': u'More cauliflower'},
    {u'text': u'Just food in general'}],
   u'question_id': u'92a9a918-b8c2-4535-e017-9c7cbd399a66',
   u'question_text': u'How many of these would you eat?',
   u'question_type': u'checkbox'},
  {u'answers': [{u'text': u'Harry Potter'},
    {u'text': u'Star Trek'},
    {u'text': u'Red vs. Blue'}],
   u'question_id': u'325519b7-92eb-47e1-cd70-49fe25ca21a2',
   u'question_text': u'OK. Which is your favorite?',
   u'question_type': u'radio_button'},
  {u'max': u'7',
   u'min': u'1',
   u'question_id': u'737c838b-3cb7-4d69-e4cc-16e90b1e4ff4',
   u'question_text': u'How much do you crave Chipotle today, on a scale of 1-7?',
   u'question_type': u'slider'},
  {u'question_id': u'c36ded54-bf41-45de-9bfe-240845fe87c2',
   u'question_text': u'This is just a piece of information- nothing to answer here.  Please move on to the next question.',
   u'question_type': u'info_text_box'},
  {u'question_id': u'a135435a-6d0b-437d-9312-4de6f828b11f',
   u'question_text': u'What do you think is the ideal number of surveys to take in a day?',
   u'question_type': u'free_response',
   u'text_field_type': u'NUMERIC'}],
 u'settings': {u'number_of_random_questions': 3,
  u'randomize': False,
  u'randomize_with_memory': True,
  u'trigger_on_first_download': True},
 u'survey_type': u'tracking_survey',
 u'timings': [[34320, 77520],
  [34320, 77520],
  [34320, 77520],
  [34320, 77520],
  [34320, 77520],
  [34320, 77520],
  [34320, 77520]]}

Rewrite/refactor the Handlebars.js components into AngularJS

This is lower priority than supporting skip logic, but it's in the same task spec in case refactoring into AngularJS makes it easier to support skip logic.

AngularJS is already used in one piece of the repo (a search filter, code for which is in frontend/templates/navbar.html and frontend/static/javascript/search_filter.js). It references a copy of the AngularJS code at frontend/static/javascript/libraries/angular.min.js.

Clone this wiki locally