Building a Quiz Manager for jQuery Mobile

This post is more than 2 years old.

A few weeks ago a reader asked if I had ever designed a quiz for jQuery Mobile. While I had not, I spent some time thinking about how a quiz could be designed as well as how a generic library could help automate it. I've built a demo I'd like to share with folks. It is definitely "First Draft" (but hey, it lints!) so feel free to tear it apart and suggest improvements.

I began by thinking how quiz data could be represented. I figured either XML or JSON. JSON has the benefit of being really easy to work with in JavaScript. XML has the benefit of being really easy to write, even for non-devs. At the end of the day though I settled on JSON. My library could be updated to handle both though. Here is an example quiz I used for my demo.

	"introduction":"This quiz tests you about foo and goo", 
		{"question":"Why is the sky blue?", 
		 "answers":["Unicorns","Fairies","Boring Science","Kittens"],
		{"question":"Why are kittens so cute?", 
		 "answers":["Magic","Fur","Meow","More Kittens!"],

The scheme consists of an optional introduction and an array of questions. Each question has a question value (the actual text), an array of answers, and a correct index. This is 0-based but I'm thinking it may make sense to be 1-based. My design only allows for multiple choice questions with one answer, but you could also do true/false of course.

On the jQuery Mobile side, the library is used by running an execute method. The execute method takes the URL of a quiz, a DOM element to render the quiz within, and a success callback. My jQuery Mobile application uses this app.js file to handle that aspect:

/* global $,document,console,quizMaster */
$(document).ready(function() {
	$(document).on("pageshow", "#quizPage", function() {
		console.log("Page show");
		//initialize the quiz
		quizMaster.execute("q1.json", ".quizdisplay", function(result) {
			console.log("SUCESS CB");

I whipped up a quick jQuery Mobile application with two pages. The first simply links over to the quiz page.

Once you load the quiz page, the code you see above runs the library. Here is how the quiz displays the introduction:

And this is the first question:

Ok, now let's look at the library.

/* global $,window */
var quizMaster = (function () {
	var name;
	var data;
	var loaded = false;
	var displayDom;
	var successCbAlias;

	function nextHandler(e) {

		var status = getUserStatus();

		//if we aren't on the intro, then we need to ensure you picked something
		if(status.question >= 0) {
			var checked = $("input[type=radio]:checked", displayDom);
			if(checked.length === 0) {
				//for now, an ugly alert
				window.alert("Please answer the question!");
			} else {
				status.answers[status.question] = checked.val();	

	function displayQuiz(successCb) {

		//We copy this out so our event can use it later. This feels wrong
		successCbAlias = successCb;
		var current = getQuiz();
		var html;

		if(current.state === "introduction") {
			html = "<h2>Introduction</h2><p>" + current.introduction + "</p>" + nextButton();
		} else if(current.state === "inprogress") {
			html = "<h2>" + current.question.question + "</h2><form><div data-role='fieldcontain'><fieldset data-role='controlgroup'>";
			for(var i=0; i<current.question.answers.length; i++) {
				html += "<input type='radio' name='quizMasterAnswer' id='quizMasterAnswer_"+i+"' value='"+i+"'/><label for='quizMasterAnswer_"+i+"'>" + current.question.answers[i] + "</label>";
			html += "</fieldset></div></form>" + nextButton();
		} else if(current.state === "complete") {
			html = "<h2>Complete!</h2><p>The quiz is now complete. You got "+current.correct+" correct out of "+data.questions.length+".</p>";
		//Remove previous if there...
		//Note - used click since folks will be demoing in the browser, use touchend instead"click", ".quizMasterNext", nextHandler);
		//Then restore it
		displayDom.on("click", ".quizMasterNext", nextHandler);
	function getKey() {
		return "quizMaster_"+name;	
	function getQuestion(x) {
		return data.questions[x];	
	function getQuiz() {
		//Were we taking the quiz already?
		var status = getUserStatus();
		if(!status) {
			status = {question:-1,answers:[]};
		//If a quiz doesn't have an intro, just go right to the question
		if(status.question === -1 && !data.introduction) {
			status.question = 0;

		var result = {
		if(status.question == -1) {
			result.state = "introduction";
			result.introduction = data.introduction;	
		} else if(status.question < data.questions.length) {
			result.state = "inprogress";
			result.question = getQuestion(status.question);	
		} else {
			result.state = "complete";
			result.correct = 0;
			for(var i=0; i < data.questions.length; i++) {
				if(data.questions[i].correct == status.answers[i]) {
		return result;
	function getUserStatus() {
		var existing = window.sessionStorage.getItem(getKey());
		if(existing) {
			return JSON.parse(existing);
		} else {
			return null;
	function nextButton() {
		return "<a href='' class='quizMasterNext' data-role='button'>Next</a>";	
	function removeUserStatus(s) {
	function storeUserStatus(s) {
		window.sessionStorage.setItem(getKey(), JSON.stringify(s));
	return {
		execute: function( url, dom, cb ) {
			//We cache the ajax load so we can do it only once 
			if(!loaded) {
				$.get(url, function(res, code) {
					//Possibly do validation here to ensure basic stuff is present
					name = url;
					data = res;
					displayDom = $(dom);
					loaded = true;
			} else {

There's a lot here and I'll try to explain it bit by bit. The end of the code is the public API which - for now - has one method, execute. Note how we detect if the quiz is already loaded. This way we can cache the JSON and not load it after we've fetched it once in the request.

displayQuiz is the main handler for rendering the quiz. It begins (ignore the copy statement) by calling getQuiz. getQuiz handles interfacing with the quiz data as well as the user data. I'm using sessionStorage to remember where you are in the quiz. This is useful if you leave the quiz before finishing it. getQuiz also does some intelligent handling of state. So for example, if there isn't an introduction it ensures you go right into the first question. It also recognizes when you're done and checks your work.

Back in displayQuiz we use the result of getQuiz to render one of three states - the introduction, the quiz itself, or the completion. By the way, the success callback is used to allow your calling code to record the results to your server via AJAX, or do anything really.

All in all this was fun to write, but as I said, feels very much like a first draft. Want to try it yourself? Hit the demo link below.

Raymond Camden's Picture

About Raymond Camden

Raymond is a senior developer evangelist for Adobe. He focuses on document services, JavaScript, and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA

Archived Comments

Comment 1 by Josh Slebodnik posted on 12/5/2013 at 10:43 PM

Perfect timing for this post because I may be creating a Quiz app for a city using Phonegap!! This will definitely help out! Thanks!

Comment 2 by Johan posted on 12/6/2013 at 9:27 AM

I built something similar a while back using jQuery but not mobile. It shows correct/incorrect as you proceed and allows timed quiz. The quiz and settings are stored in Google spreadsheet. You may get a error on first load - just reload - it's due to a bug in connecting to YQL which parses spreadsheet.

Comment 3 by Raymond Camden posted on 12/6/2013 at 6:15 PM

A bit OT - but YQL is cool. I remember finding it years ago and it gets almost no press. I rarely hear developers talk about it.

Comment 4 by Okezie Michael posted on 12/6/2013 at 7:36 PM

Hello Ray,

Nice work, i think we should have something like a review after the Quiz, and a button to re-take the Quiz again. and re-taking the Quiz, the question should shuffle , so i think if you can increase the number of Questions in the Question bank to 5, to check that it shuffles on re-taking the Quiz.

if you can please email me your source code and let me add these features, i don't know why am getting an error.




Comment 5 by Raymond Camden posted on 12/6/2013 at 7:38 PM

Okezie: Yeah, I was a bit torn between how much the "Manager" should do versus how much you (you being the person using the manager) should do too. I thought about providing a way to let you do the 'Your done' message yourself, but decided against it.

Anyway - there is no need for me to send you the code... just view source and save. :) (Obviously you will need to grab the JS files manually.)

Ok screw it - give me a minute and I'll post up a zip.

Comment 6 by Raymond Camden posted on 12/6/2013 at 7:39 PM

Zip is located here:

Comment 7 by Phillip Senn posted on 12/6/2013 at 10:57 PM

I teach an online class, and have had an observation the other night about students taking quizzes online. I think that the traditional thought of quizzing doesn't apply to online students any longer. #1 it's always been assumed that an online quiz is an open book, open Google search assignment.

But what I found was that students were simply answering questions without even reading the textbook OR doing a Google search. In other words, the quiz itself needs to do the teaching and become the verification that the teaching has been understood. So instead of the normal Question and Answer, I think online quizzes need to be: teaching and verifying.

Might seem obvious, but just something that I wanted to put on the table.
Run it up the flag pole and see who salutes it.
Swing for the fences.
I'm just throwing something up against the wall and seeing what sticks.
A penny saved is a penny earned.

Comment 8 by Raymond Camden posted on 12/6/2013 at 11:01 PM

Interesting comment there, Phillip. Do you have an example of one online that does this? (Hopefully something easy for folks to see - ie no sign up.)

Comment 9 by Jack posted on 12/7/2013 at 12:07 AM

I know this is just a demo, but it seems to me that from a quiz-creation standpoint it would be better to have the answer be the actual answer (as a string) rather than a numeric index:
{"question":"Why is the sky blue?",
"answers":["Unicorns","Fairies","Boring Science","Kittens"],

One drawback of this approach is that a typo in the answer would mean that the code would never find a correct match. (Presumably this would be detected through testing or a quiz validation function.)

However, it comes with several advantages
-- Would make it easier to change the order of the multiple choice responses. This would be really helpful if you reshuffled the questions and presented them again and didn't want them to look exactly the same.
-- Would allow another reviewer to easily validate a test created by a colleague.
-- Would eliminate all off-by-one errors!!!!

Comment 10 by Raymond Camden posted on 12/7/2013 at 12:20 AM

Jack and I discussed this in email and I asked him to bring here as I thought it would be good for the conversation. I was opposed to this because of the concern with possibly mistyping the answer. *But* - if there was validation at the quiz library level I think this would be a good change actually.

Comment 11 by Tim posted on 12/10/2013 at 2:46 PM

I downloaded the script, and when I run it in firefox and click "Start Quiz!", it shows the quiz.html page but has no questions or footer content there, why is that :S

Comment 12 by Raymond Camden posted on 12/10/2013 at 4:19 PM

@Tim: Check the console - do you see an error?

Comment 13 by Tim posted on 12/11/2013 at 8:57 AM

I'm seeing the same problem as the other Tim. Downloaded the .zip file, extracted, double-clicked on index.html, click the Start Quiz button - then only see the header and footer, nothing in the content area. I notice sometimes when viewing the demo on your site it does the same thing - where the actual quiz should be, only a header and footer show up.

Console will log out "Page show" then gives a "not well-formed" for both q1.json and quiz.html; it never seems to make it to log out the "SUCESS CB" line. This is on Firefox 26; tried on IE and Chrome - IE will work on site, but not when downloaded to my computer. Chrome gives the following console error:

No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.

This is why javascript so often tastes like headache =/

Comment 14 by Raymond Camden posted on 12/11/2013 at 6:14 PM

Lets focus on Chrome for now. When you run it, are you running it from a local web server, or did you just double click on the file?

Comment 15 by Captain Obvious posted on 12/16/2013 at 9:00 PM

For those getting an error add "json" mime type to web server config or change line #141 in quiz.js from this


to this

}, "json" );

Comment 16 by Raymond Camden posted on 12/16/2013 at 11:30 PM

Darn good point there Captain Obvious. Thanks. (Hopefully the Captain Obvious wasn't a dig at me for missing something obvious. ;)

Comment 17 by Captain Obvious posted on 12/16/2013 at 11:57 PM

No no - that is just my gmail handle :)

Comment 18 by Albert posted on 1/5/2014 at 2:50 AM

Great tutorial as usual, thanks. I'm going to use it in my phonegap app and therefore wanted to ask you about some advices for adapting your code for running it locally rather than from web server. Thanks in advance.

Comment 19 by Raymond Camden posted on 1/6/2014 at 3:46 AM

The code is just HTML/JS/CSS. It should run just fine in PhoneGap.

Comment 20 by Albert posted on 1/7/2014 at 4:13 AM

I've tried already to run it on phonegap. It causes Uncaught TypeError: Cannot read property 'length' of undefined at file:///android_asset/www/quiz.js:92

Comment 21 by Captain Obvious posted on 1/7/2014 at 6:11 PM

Albert - you will get that error if "data" is a string rather than a json object, note my comment above.

Comment 22 by Albert posted on 1/7/2014 at 7:03 PM

Captain Obvious - thanks for the reminding again :) the changes in 141 line of quiz.js solved the problem :)

Comment 23 by Kane posted on 2/17/2014 at 5:04 PM

Tim, were you able to fix the No 'Access-Control-Allow-Origin'' error?

Raymond - thank you for putting this together.
Downloaded the .zip and clicked index.html, it runs perfectly fine in Firefox, however in Chrome and IE I get the following errors as soon as clicking the "Start Quiz" button:

1) Failed to load resource: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.

2) XMLHttpRequest cannot load file:///C:/Users/Kane/Desktop/New%20folder/quiz/quiz.html. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.

Any idea's? I made the change to 141 on quiz.js...

Comment 24 by Raymond Camden posted on 2/17/2014 at 5:06 PM

The answer is simple - don't run it from the file system. Just run it on a 'real' web server, like Apache, or IIS. Or try httpster.

Comment 25 by Kane posted on 2/17/2014 at 7:25 PM

Raymond - that worked, thanks!

Comment 26 by Raymond Camden posted on 2/17/2014 at 7:28 PM

As an FYI, I strongly recommend doing *all* HTML work on a real web server. A *lot* of stuff acts differently when opening via file:///.

Comment 27 by Sachin Tehare posted on 3/13/2014 at 5:27 PM

I am not able to get correct answers count on my result page.
Can you please guide me.

Comment 28 by Raymond Camden posted on 3/14/2014 at 7:37 PM

Where is your copy of the app so I can test it?

Comment 29 by saad posted on 3/15/2014 at 5:37 PM

it works thank you, but I need two things :
1- get a random question every time and increment randomly too ?
2- display correct answer before quitting the current question ??

Comment 30 by Raymond Camden posted on 3/15/2014 at 6:07 PM

Well, that's certainly doable. :) I don't have that written but it is definitely something you could do.

Comment 31 by saad posted on 3/15/2014 at 7:26 PM

can you show me how to do it ? may be initiate i variable by Math.random() .!!

Comment 32 by Raymond Camden posted on 3/16/2014 at 7:03 AM

Sorry - no - it isn't something I'll have time to do. You can do it yourself - you already have an idea about using Math.random - just keep at it.

Comment 33 by Imran Khan posted on 5/13/2014 at 10:50 AM

When i click on start quiz , the quiz section is not loading, i checked in browser also. I am doing for phone gap

Comment 34 by Raymond Camden posted on 5/13/2014 at 5:45 PM

Please open the console and tell me if you see an error.

Comment 35 by Sasha posted on 5/20/2014 at 5:43 AM

Hi, I can't seem to get this working, When i follow the instructions and copy the code t all works perfectly but if I change any questions then nothing shows up at all, even just changing the first question from 'blue' to 'red' makes nothing show up, I'm probably missing something very easy. this is my first time using json any help would be very welcome. Thanks :)

Comment 36 by Raymond Camden posted on 5/20/2014 at 5:51 AM

Can you put it online where I can see?

Comment 37 by Sasha posted on 5/20/2014 at 6:06 AM

Hi sorry it's the website I entered on the comments form :) I thought it would show up, here it is the only thing changed from your code is one word in a question on the json file.

Thanks so much.

Comment 38 by Raymond Camden posted on 5/20/2014 at 7:03 AM

I copied the URL of your JSON file to a JSON validator, and it said there was an error. Go here and paste in and validate. You will see.

And.... I see it now. Go the URL (the JSON url) in a new tab and you will see a special character at the end of the first question value. You may have pasted something there by accident.

Comment 39 by Sasha posted on 5/20/2014 at 8:02 AM

I found the error, thank you so much, I never even thought of using a validator, Thanks again you've saved my project.

Comment 40 by Saurya posted on 5/20/2014 at 1:54 PM

I used your code and developed an app with phonegap build but the app is not working after i clicked on quiz . I think this is because phonegap doesnot support json file.Am i right?

Comment 41 by Raymond Camden posted on 5/20/2014 at 3:23 PM

@Sasha: It looked pretty cool, would you mind posting here when it is done so I can see it?

@Saurya: PhoneGap *definitely* supports JSON. Perhaps you made the same mistake as Sasha? Try using remote debug to see if you see an error.

@Sasha and All: If I had added a proper error handler to $.get, this would have shown up. Sorry!

Comment 42 by Saurya posted on 5/20/2014 at 3:36 PM

I dont know how to use remote debugger. Can you please make me understand about the error which may be occuring in my code.

Comment 43 by Saurya posted on 5/20/2014 at 3:49 PM

when i am running the code on desktop browser its running fine but app is not working

Comment 44 by Raymond Camden posted on 5/20/2014 at 3:55 PM

@Saurya: Go to the About Me link on top and look at my list of articles. I've got two articles on remote debugging.

Comment 45 by Saurya posted on 5/20/2014 at 8:20 PM

I found my mistakes. Thank you so much

Comment 46 by Sasha posted on 5/21/2014 at 5:14 AM

@Raymond Camden heres the link to the quiz.. hope u like it :)

Comment 47 by Raymond Camden posted on 5/21/2014 at 5:18 AM

Very cool! FYI, typo here: They Asian Elephant and?

Comment 48 by denny posted on 5/28/2014 at 6:15 PM

thank u so much sir for this guide...
but i want to add multiple subject wise quiz , let say, two questions of english subjet & two for if i select english from drop menu then it should show english's questions otherwise it shouls show as continously....

Comment 49 by denny posted on 5/28/2014 at 6:17 PM

My json file is -
"introduction":"This quiz tests you about foo and goo",
{"question":"Why is the sky blue?",
"answers":["Unicorns","Fairies","Boring Science","Kittens"],
{"question":"Why are kittens so cute?",
"answers":["Magic","Fur","Meow","More Kittens!"],
"introduction":"This quiz tests you about foo and goo",
{"question":"Why is the sky blue?",
"answers":["Unicorns","Fairies","Boring Science","Kittens"],
{"question":"Why are kittens so cute?",
"answers":["Magic","Fur","Meow","More Kittens!"],

Comment 50 by Raymond Camden posted on 5/28/2014 at 6:19 PM

My code doesn't support that. :) It is definitely doable, but you would need to modify the code.

Comment 51 by denny posted on 5/28/2014 at 6:24 PM

yes sir, it's working fine ...thank u sir

Comment 52 by dhas posted on 7/30/2014 at 3:21 PM

where i include the json file. its not working me. please include q1.json file in the html.

Comment 53 by Raymond Camden posted on 7/30/2014 at 4:08 PM

The JSON file is loaded by the JavaScript code, not HTML.

Comment 54 by dhas posted on 7/31/2014 at 7:38 AM

I extracted the file and place in server http://education.pelicanbro.... its working. the same setup i place it in apache server in the LAN environment. The quiz is not viewing. please help me is there any constraint is there.

Comment 55 by Raymond Camden posted on 7/31/2014 at 3:11 PM

When you open up your dev tools in your browser, do you see any issues?

Comment 56 by saad posted on 8/3/2014 at 5:13 PM

Why it doen't works when include remote json file in app.js :
quizMaster.execute("http://localhost/Q.json", ".quizdisplay", function(result) {
do you have any idea why it doesn't works ??

Comment 57 by Raymond Camden posted on 8/3/2014 at 6:58 PM

That's browser security rules. If you want to call a JS file on another server, you have to either use JSON/P or CORS.

Comment 58 by saad posted on 8/3/2014 at 10:57 PM

When I use an external file like json or even a php file that echo a json output ... not working either ... do I need to change something in quiz.js ?? if I use this application in intellxdk or phonegap, will it works on mobile devices !??

Comment 59 by Raymond Camden posted on 8/3/2014 at 11:34 PM

Please read my last comment as I told you exactly why it would fail and 2 possible work arounds.

In Cordova this won't be an issue as Cordova apps can get JSON data via XHR to any domain.

Comment 60 by Rodrigo da Costa Barros Macedo posted on 8/8/2014 at 6:49 PM

I really liked this example. I wonder if this has a similar loading questions from a php server instance? And another, how to generate build this application for android?

Comment 61 by Raymond Camden posted on 8/8/2014 at 6:53 PM

You could just generate the JSON data from PHP.

As for building this for Android, you could do it with PhoneGap/Cordova.

Comment 62 by Rodrigo Macedo posted on 8/8/2014 at 9:35 PM

Have an example with php server or at least know where you have indicated?
For understand the Sencha Touch framework but still could not make a quiz application I want to see if I can with JQuery Mobile

Comment 63 by Raymond Camden posted on 8/8/2014 at 10:15 PM

I don't use PHP so I can't help you with that. Did you google for PHP and JSON? I'm sure there is a simple way to do it.

Comment 64 by Omer Rosenbaum posted on 8/9/2014 at 9:59 PM

Is there an address where I can download the files?
I have some errors and I want to compare to the original script.

Comment 65 by Raymond Camden posted on 8/9/2014 at 10:11 PM

Unfortunately no - but you can right click/download from the demo. And grab the JS file referenced. It's all there - just have to manually grab em.

Comment 66 by Omer Rosenbaum posted on 8/9/2014 at 10:18 PM

You mean the app.js and quiz.js?

Comment 67 by Raymond Camden posted on 8/9/2014 at 10:36 PM

Just use your Dev Tools. :)

app.js -
quiz.js -

Comment 68 by Rodrigo Macedo posted on 8/26/2014 at 3:57 PM

I modified the questions in q1.json but they did not alter the application which can be

Comment 69 by Raymond Camden posted on 8/26/2014 at 4:24 PM

Try clearing your browser cache.

Comment 70 by Rodrigo Macedo posted on 9/29/2014 at 3:47 PM

Good day I link back to this application as another I'm doing all the files were loaded only q1.json file was not loaded and not changed anything in the file app.js. What can be done? Is to make the direct manipulation of the questions in the app.js file? If so, how should it be done? Ja the app.js file loads and the q1.json not charging. Thanks in advance

Comment 71 by Raymond Camden posted on 9/29/2014 at 3:49 PM

I'm sorry, but I cannot understand your English. Can you try again?

Comment 72 by Rodrigo posted on 9/30/2014 at 4:41 PM

Well what I meant and that direct testing this application it works because it loads the file q1.json. However I created an application and a redirect link to this quiz app. The files are all loaded in the q1.json exception. So quiz.html of the page is blank. What can it be? Is to store the contents of the file within q1.json app.js?

Comment 73 by Raymond Camden posted on 9/30/2014 at 5:18 PM

I'm afraid I still can't understand your English.

What is a "redirect link to this quiz app" - are you saying your app literally sends people back to my code?

"The files are all loaded in the q1.json exception."
This makes no sense at all.

It sounds like you *may* be trying to load q1.json from a different domain than the one hosting your app. If so, you can't, unless you make use of CORS or JSON/P.

Comment 74 by Erik posted on 1/29/2015 at 3:19 PM

I downloaded the quiz, but when i tried it (before changing anything) with Chrome it didn't work. I open index.html, clicked start quiz, and than i got a message that says: Error Loading Page.

How can i fix this, because i need it for a school assignment (very soon).

Comment 75 (In reply to #74) by Raymond Camden posted on 1/29/2015 at 6:50 PM

Are you running it on a local web server, or from the file system?

Comment 76 by Paul Tucker posted on 1/13/2017 at 8:46 AM

This is really interesting.
I get a zero kb 'download' file (without extension). Is there any other links to the source for the demo, please?
Thank you.

Comment 77 (In reply to #76) by Raymond Camden posted on 1/13/2017 at 3:34 PM

Sorry, add index.html to the URL. Unfortunately some of the scripts won't load because they use http. Not sure when I'll fix that, but at least for right now you can view source and download.

Comment 78 (In reply to #77) by Raymond Camden posted on 1/13/2017 at 3:51 PM

And it should be working online now. I'll fix the link here too, but that won't online until I blog again.

Comment 79 by Paul Tucker posted on 1/13/2017 at 6:57 PM

Thanks - now working with the index.html suffix.
URL changes to a suffix of quiz.html once it's run. and index.html needs to be reloaded.
Probably me - on a steep learning curve!