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!