Press "Enter" to skip to content

Survey Builder Design

Last updated on Monday, December 7, 2015

One of my first projects after joining the APEX team was creating the Survey Builder packaged application (available in Oracle Application Express 4.2.2). This was my first experience creating an APEX app. A number of people helped out on the implementation (especially on reports) and also helped me learn APEX. I worked on the overall design and functionality and focused on implementing the questionnaire page and questionnaire editing page, both of which required lots of JavaScript. The paper Designing an Effective Survey by Mark Kasunic provided invaluable background information on the survey process and I recommend it to anyone new to conducting survey research.

Survey Builder is a little different from typical APEX apps (if there even is such a thing as a typical APEX app). Here I want to describe a couple of requirements that shaped its design and the resulting APEX implementation. A great thing about APEX is that it comes with a number of fully functional packaged applications such as Survey Builder that you can use as-is, tweak to do what you want or just open up to see how it works. So feel free to install Survey Builder, unlock it, and follow along.

Questionnaire Editing

Creating and editing the questionnaire needs to be as effortless as possible. The questionnaire is made up of sections, sections have questions, and most questions have multiple choice answers. There are separate tables for each of those entities. A naive implementation would have a report page listing sections clicking a section would lead to a section details page and each section details page would have a report listing questions and so on. Editing the questionnaire would require a lot of navigation between pages and it would be hard to visualize the questionnaire as a whole. Master detail style pages would help but still wouldn’t let you see the whole questionnaire at once. I wanted to use a document outline metaphor and have all editing done on a single page to eliminate navigating between pages. Details for sections, questions and answers are added/edited using dialogs. Reordering is done directly on the outline with drag and drop. The outline can be expanded or collapsed to see everything or focus in on just the area of interest.

APEX doesn’t have an out-of-the-box UI control like that. I wouldn’t expect any widget framework to have exactly what I was looking for. A tree comes close but I wanted full control over the rendering and behavior including full keyboard accessibility. Since the questionnaire is core functionality for any survey app, to me this is a case where it is worth the extra effort to create a custom UI control.

APEX allows you to add your own JavaScript and CSS to pages so anything a browser can do can be done with APEX. APEX plugins provide a nice way to package up custom UI in to a reusable unit but this questionnaire outline is very specific to Survey Builder so a plugin was not used.

APEX makes use of jQuery and jQuery UI for its own UI components. Other jQuery UI widgets are also available. You just have to include the corresponding JavaScript file and call the widget from your own JavaScript. I used connected jQuery UI sortable widgets for drag and drop reordering. The dialogs are also from jQuery UI. APEX Dynamic Actions (DA) are the glue between event driven client behavior and server side processing. DAs allow you to transfer page item data, and execute JavaScript code, and/or PL/SQL code in response to an event. For example when you edit the details of a question, a DA is used to fetch the question data to show in the dialog (the dialog is a hidden region on the page). Then when you click the Apply Changes button another DA is used to send the data to the server, validate and persist it.

Filling out Questionnaires

It’s important to be respectful of people’s time when they are taking your survey. For the survey author this means keeping the length of the questionnaire reasonable. For the survey software this means questionnaires must load quickly, be pleasant to look at, be usable and accessible, work with different devices and screen sizes, and save the response quickly.

The questionnaire is essentially a very simple web application. It’s just a web form with a few kinds of form fields. Survey Builder is responsible for creating any number of these simple questionnaire web applications.

At the intersection of simple constrained UI and fast load times I saw an ideal use case for a thin server web app. A thin server web app is one where all the markup is static (as opposed to generated for each request), data is inserted into the UI on the client side, and the interchange of data between client and server uses XMLHttpRequest (ajax).

Now APEX pages load pretty quickly but the questionnaire is so simple that it doesn’t need all the power of APEX. A couple key tenets of front end web performance are to keep the pages small and the requests few. The questionnaire doesn’t need most of the APEX JavaScript or theme CSS. Even my favorite JavaScript library, jQuery, is overkill in this case. The questionnaire is a single HTML page even when it appears to have each section or question on a separate page. It includes all CSS and JavaScript inline. The JavaScript doesn’t include or use any third party libraries. This keeps the page very small. For example the sample toaster survey HTML page (including all CSS and JavaScript) is under 60K (before gzip compression), which is smaller than the minified jQuery library alone. The only external resource is a small sprite image.

If you look at any questionnaire page you will notice that it uses a normal APEX URL. All questionnaires are page Q, which is an alias for public page 100. The request field of the APEX URL identifies which questionnaire to return. The single parameter, code, is a unique code for each respondent in a random-sample survey. The URL is where any similarity with normal APEX pages ends. If you look at the page source you will notice that it is not a normal APEX page at all. The best indication is that the form action is not “wwv_flow.accept” and the standard hidden inputs such as pFlowId are not present.

Here’s how it all works. When you click the preview button or put the survey into Test or Active state the render_questionnaire procedure in package eba_sb is called to generate the questionnaire HTML page and store it as a blob. To keep the code modular and easy to modify the render_questionnaire procedure reads inline JavaScript and CSS from blobs in table apex_application_files. When a request for page Q (100) is made the questionnaire page blob is returned. Page 100 has a minimal page template and no regions because the APEX rendering is not going to be used. An after footer process sends the static blob and sets wwv_flow.g_page_text_generated to true to let APEX know that the page has already been rendered. This is reasonable because the questionnaire doesn’t change so no need to keep regenerating the same thing for each request. Another reason it is easy to have a static questionnaire page is that it doesn’t need to be localized. You can create a questionnaire in any language but each questionnaire is in a single language. Questionnaire forms are always initially empty so there is no need insert data into the markup either. Even if a feature to allow saving answers and returning to the survey later were implemented in the future the page would still be static and the previous saved values would be set after the initial ajax request.

When the questionnaire Submit button is pressed the answers are validated on the client side and if there are no errors an ajax request is sent to an AJAX callback page process on page 100. That process must also validate the answers. If all validations pass the answers are stored.

Summary

Each application is different. Some will require custom UI. Probably few will need to generate static pages. Even if the designs described above don’t apply to your application I hope one take-away is that APEX is a very flexible and capable framework.