Customizing #Episerver.Forms with client events, build a quiz
Example of using client side events to tweak and customize the output and displaying result depending of input values.
Published 27th of October 2017
Episerver Forms > v2
Storyboard:
- quiz
- multiple steps
- last step display result
- and possibility to post your result (on a board or for a contest)
We will use the jQuery formsSetupCompleted and formsNavigationNextStep to do our client side customizations.
Available events are:
- formsNavigationNextStep
- formsNavigationPrevStep
- formsSetupCompleted
- formsReset
- formsStartSubmitting
- formsSubmitted
- formsSubmittedError
- formsNavigateToStep
- formsStepValidating
This example uses this setup:

On the question (single choice) elements i choosed to set 1 (one) for the right answer and 0 (zero) on wrong.

Then later in the javascript I just sum radio buttons in form and divide with total radios, so I get a percent.
The Rich Text Element in result step displays a progress bar and then uncovers a div depending on result in previous steps:
<div class="result full"> <div class="progress"> <div class="progress-bar" style="width: 0%;"> </div> </div> <div class="resulttext"> <h4 style="font-size: 50px;"><span style="color: lightgray;">Good</span> <span style="color: lightgray;">Better</span> Best</h4> <p>You are simply the best, you should come work with us! Please supply your contact information and we will but you on our ranking board. </p> </div> </div> <div class="result half"> <div class="progress"> <div class="progress-bar" style="width: 0%;"> </div> </div> <div class="resulttext"> <h4 style="font-size: 50px;"><span style="color: lightgray;">Good</span> Better <span style="color: lightgray;">Best</span></h4> <p>Thats a great result, most devs doesn't even come this far! </p> </div> </div> <div class="result zero"> <div class="progress"> <div class="progress-bar" style="width: 0%;"> </div> </div> <div class="resulttext"> <h4 style="font-size: 50px;">Good <span style="color: lightgray;">Better</span> <span style="color: lightgray;">Best</span></h4> <p>You seem competent, but maybe you should try again. </p> </div> </div> <h3>Supply your score to our ranking board</h3>

Result_Percent and Result_Grade: I use predefined hidden inputs to save the score when submitted.
After submission:
Back-end:

<div class="result half full"> <h1>Thank you</h1> <p>We will put you on our ranking board</p> </div> <div class="result zero"> <h1>To bad you didn't make it</h1> <p>Better luck next time!</p> </div>
Display:


The code:
Made a quizblock just to package form with javascript, I use it to ouput my javascript, only on pages when this block is used, thru EPiServer.Framework.Web.Resources.ClientResources.RequireScript(“/static/js/quizblock.js”).AtFooter();
@model Gosso.Models.Blocks.QuizBlock
@{
EPiServer.Framework.Web.Resources.ClientResources.RequireScript("/static/js/quizblock.js").AtFooter();
}
<div class="quizBlock">
@Html.PropertyFor(x => x.TopContentArea, new { CssClass = "row block-container" })
</div>
using System.ComponentModel.DataAnnotations;
using EPiServer.Core;
using EPiServer.DataAbstraction;
using EPiServer.DataAnnotations;
namespace Gosso.Models.Blocks
{
[ContentType(
DisplayName = "Quiz block",
Description = "Block to create Quiz with Episerver Forms",
GroupName = SystemTabNames.Content,
AvailableInEditMode = true)]
public class QuizBlock : BlockData
{
[Display(
Name = "Block full width",
GroupName = SystemTabNames.Content,
Order = 8
)]
public virtual ContentArea TopContentArea { get; set; }
}
}
The javascript
if (typeof $$epiforms !== 'undefined') {
$$epiforms(document).ready(function myfunction() {
var ShowResult = function ($htmlblock, procent) {
$htmlblock.find("h4,p").hide();
$htmlblock.show();
$htmlblock.find(".progress .progress-bar").animate({
width: procent + "%"
}, 800);
setTimeout(function () { $htmlblock.find("h4").slideDown(); }, 1800);
setTimeout(function () { $htmlblock.find("p").slideDown(); }, 2800);
};
$(".EPiServerForms .result").hide();//hide everything on init
var formResult = "Good";
$$epiforms(".EPiServerForms").on("formsNavigationNextStep formsNavigationPrevStep formsSetupCompleted formsReset formsStartSubmitting formsSubmitted formsSubmittedError formsNavigateToStep formsStepValidating", function (event, param1, param2) {
console.log(event.type, event); //for fun
//which step am i on?
var lastStep = (event.targetStep!== undefined && event.workingFormInfo.StepsInfo.Steps.length === event.targetStep.index + 1);
var firstStep = (event.targetStep !== undefined && event.targetStep.index===0);
if (event.type === "formsSubmitted" && event.isFinalizedSubmission) {
//cool, its submitted, setTimeout because AJAX call
setTimeout('filterQuizResult("' + formResult + '")', 100);
}
else if (event.type === "formsNavigationNextStep") {
if (lastStep) {
//Count the score
var summa = 0;
var counter = 0;
//for each radiobutton in this form
$(this).find(".FormChoice__Input--Radio:checked").each(function() {
counter++;
summa = eval(summa + parseInt(this.value));
});
var procent = summa / counter * 100;
console.log("formsNavigationNextStep sum", summa);
console.log("formsNavigationNextStep count", counter);
console.log("formsNavigationNextStep procent", procent);
$(this).find(".result").hide();//initial
if (procent >= 100) { //depending on percent
ShowResult($(this).find(".result.full"), 100);
formResult = "Best";
} else if (procent > 66) {
ShowResult($(this).find(".result.half"), procent);
formResult = "Better";
} else {
ShowResult($(this).find(".result.zero"), procent);
formResult = "Good";
}
$(this).find(".Form__Element.FormHidden").val(procent); //save to hidden element
$(this).find(".Form__Element.FormHidden.Result_Grade").val(formResult); //save to hidden element
$(this).find(".btnNext").hide();
}
$(this).find(".btnPrev").show();
}
else if (event.type === "formsSetupCompleted") { //setup complete, customize the navigationbar
$(this).find(".btnPrev").hide();
$(this).find(".Form__NavigationBar__ProgressBar--Progress").hide();
$(this).find(".Form__NavigationBar__ProgressBar").hide();
$(this).find(".FormChoice__Input--Radio:checked").each(function () {
this.checked = ""; //default reseting
});
}
else if (event.type === "formsNavigationPrevStep" || event.type === "formsReset") {
if (firstStep)
$(this).find(".btnPrev").hide();//dont show on firststep
$(this).find(".btnNext").show();
}
});
});
}
function filterQuizResult(formResult) {
if ($(".Form__Success__Message").length > 0) { // check if message exists
$(".EPiServerForms .Form__Success__Message .result.full").hide();
if (formResult !== "Good") {
$(".EPiServerForms .Form__Success__Message .result").hide();
$(".EPiServerForms .Form__Success__Message .result.full").show();
} else {
$(".EPiServerForms .Form__Success__Message .result.zero").show();
}
} else {
setTimeout('filterQuizResult("' + formResult + '")', 100);//test again
}
}
Javascript console:

Email the submission looks like this:

Thoughts
- You could easily use a score system instead of percent
- There is no way to find uniq ids on element, to solve this, you need to override the element block template, check blog post on this for further reading.
Source:
SEO terms
- Extending Episerver Forms Example
- jQuery events client side tweaking
Happy forming!