Documentation v1.5.2
( all demos: basic demo - demo 1 - demo 2 )
surveyJS let's you create a survey from a JSON and manage all the process ( fields validation, local storage and JSON construction are already set )
You can manage:
surveyJS is developed with these dependencies:
<!-- BOOTSTRAP CSS --> <link rel="stylesheet" href="css/bootstrap.min.css"> <!-- AWESOME BOOTSTRAP CHECKBOX CSS ( for custom graphic inputs ) --> <link rel="stylesheet" href="css/font-awesome.css"> <link rel="stylesheet" href="css/awesome-bootstrap-checkbox.css"> <!-- SURVEY CSS --> <link rel="stylesheet" href="css/survey.css"> <!-- JQUERY --> <script src="js/vendors/jquery-1.12.4.min.js"></script> <!-- SURVEY JS ( with WEB_STORAGE and FORM modules included ) --> <script src="js/surveyJS-1.5.min.js"></script>
The demo is developed with Bootstrap 3.3.7
This is the basic HTML structure to initialize the survey ( div with class "survey-body" will be filled with questions & answers. ):
<div class="survey-cont" data-surveyjs-cont> <form action="page.jsp" name="survey-form" class="survey-form" data-surveyjs-form novalidate=""> <div class="survey-body questionsList clearfix" data-surveyjs-body></div> <div class="survey-footer"> <button type="submit">SEND</button> </div> </form> </div>
Mandatory attributes:
CSS classes ( like .survey-* ) are optional but used to give styles to the demos.
You must specify the url to retrieve the JSON data to build the survey.
SURVEY.setup({ setJSONurl: 'json/survey.json' });
Example of JSON file for the survey is here.
( image, title and description are optional )
Below the explanation of the JSON:
{ "result": "OK", // IF "OK" THE SURVEY WILL BE BUILT "survey": { "id": 0, "image": "img/survey-image.png", "title": "My Survey", "description": "Answer the questions", // LIST OF ALL QUESTIONS ( AS OBJECTS ) "questions": [ // RADIO ANSWER { // EVERY QUESTION HAS ITS OWN DATA "id": "1", "question": "Hai animali domestici?", "answers": [ // EACH ANSWER IS AN OBJECT WITH SOME DATA { "id": "1", "type": "radio", "answer": "Sì", "sort": 1 }, { "id": "2", "type": "radio", "answer": "No", "sort": 2 } ], // IF required IS FOUND, THE ANSWER FIELDS WILL HAVE THE required ATTRIBUTE (SO THIS QUESTION REQUIRE AN ANSWER) "required": "", // THE POSITION TO SET FOR THE QUESTION (USED ALSO FOR ANSWERS - SEE ABOVE) - THIS IS OPTIONAL "sort": 1 }, // TEXT INPUT ANSWER NOT MANDATORY { "id": "1b", "question": "Hai animali domestici?", "answers": [ { "id": "1ba", "type": "text", "answer": "" } ] }, // RELATED FIELD ANSWER WITH INPUT TEXT ( SEE attribute FIELD ) { "id": "5", "question": "Quanto è importante che il programma fedeltà...?", "answers": [ { "id": "19", "type": "radio", "answer": "Sia divertente" }, { "id": "20", "type": "radio", "answer": "Non richieda molto impegno di partecipazione" }, { "id": "200", "type": "radio", "answer": "Altro...", "attribute": { "id": "", "type": "text", "answers": "" } } ], "required": "", "sort": 6 }, // NESTED ANSWERS ( SEE nested ATTRIBUTE ) // RELATED FIELD ANSWER WITH SELECT FIELD ( SEE attribute FIELD ) { "id": "6", "question": "Quale MODALITÀ DI PARTECIPAZIONE al programma fedeltà preferisci?", "answers": [ { "id": "21", "type": "radio", "answer": "Sito", "nested": [ { "id": "21a", "type": "radio", "answer": "Pc", "sort": 1 }, { "id": "21b", "type": "radio", "answer": "Smartphone", "sort": 2 }, { "id": "21c", "type": "radio", "answer": "Tablet", "sort": 3 } ], "sort": 1 }, { "id": "21aPlus", "type": "radio", "answer": "Sito", "attribute": [ { "id": "21aa", "type": "option", "answer": "Pc", "sort": 1 }, { "id": "21ba", "type": "option", "answer": "Smartphone", "sort": 2 }, { "id": "21ca", "type": "option", "answer": "Tablet", "sort": 3 } ], "sort": 6 }, { "id": "24", "type": "radio", "answer": "App", "sort": 3 }, { "id": "25", "type": "radio", "answer": "Telefonica", "sort": 4 }, { "id": "26", "type": "radio", "answer": "Con utilizzo card/tessera", "sort": 5 } ], "required": "", "sort": 7 }, // CHECKBOX ANSWER WITH MULTIPLE CHOICE ( maxChoice: NUMBER OF MAXIMUM SELECTABLE ANSWERS ) { "id": "8", "question": "Cosa hai gradito di più del programma in corso?", "answers": [ { "id": "43", "type": "checkbox", "answer": "Chiarezza della comunicazione", "sort": 1 }, { "id": "44", "type": "checkbox", "answer": "Facilità e modalità di partecipazione", "sort": 2 }, { "id": "45", "type": "checkbox", "answer": "Stile del programma (grafica e linguaggio)", "sort": 3 }, { "id": "46", "type": "checkbox", "answer": "Durata del tempo di partecipazione", "sort": 4 }, { "id": "47", "type": "checkbox", "answer": "Contenuti/premi proposti", "sort": 5 } ], "maxChoice": 2, "required": "", "sort": 9 }, // SELECT ANSWER { "id": "9", "question": "Quanto è importante che il programma fedeltà sia divertente?", "answers": [ { "id": "160", "type": "option", "answer": "Poco", "sort": 1 }, { "id": "161", "type": "option", "answer": "Così così", "sort": 2 }, { "id": "162", "type": "option", "answer": "Tanto", "sort": 3 } ], "required": "", "sort": 10 }, // PRIVACY CHECK { "id": "22", "question": "hidden-privacy", "answers": [ { "id": "44", "type": "radio", "answer": "Sì" }, { "id": "45", "type": "radio", "answer": "No" } ], "required": "", "sort": 10 }, ] } }
Note:
To bind the privacy acceptance field to the survey you can set a question object as shown in the JSON above ( see PRIVACY CHECK ):
<div class="question-box" data-formjs-question=""> <div class="answers-box"> <div class="radio radio-inline"> <label> <input data-exclude-storage="" data-name="bind-survey-answer"/> <span></span> </label> </div> <div class="radio radio-inline"> <label> <input data-exclude-storage="" data-name="bind-survey-answer"/> <span></span> </label> </div> </div> </div>
Or with use of graphic inputs:
<div class="question-box" data-formjs-question=""> <div class="answers-box"> <div class="radio radio-inline"> <input data-exclude-storage="" data-name="bind-survey-answer"/> <label> <span></span> </label> </div> <div class="radio radio-inline"> <input data-exclude-storage="" data-name="bind-survey-answer"/> <label> <span></span> </label> </div> </div> </div>
You can initialize the survey with some extra options:
language for messages (eg: loading box), select default option etc...
other values: 'it'
Fires when the AJAX call ( to get the survey JSON ) ends.
Parameters:
Fires when the AJAX call ( to get the survey JSON ) throws an error.
Parameters:
Fires when all the survey is successfully loaded in the page.
Parameters:
Fires on survey form submit or when a field is not valid ans it is mandatory.
the "data" parameter is a JS object like:
{ event: 'submit', fields: [{ field: $('.myField'), result: true }] }
Fires before the AJAX call to send the data to the server.
Parameters:
If you want to edit the JSON, you MUST have a return statement with the edited JSON to send it as modified.
Fires when the AJAX call ( to submit the form ) ends.
Parameters:
Fires when the AJAX call to submit the form returns an error.
Parameters:
Fires when the AJAX call to submit the form is successfully made
Parameters:
{ validateOnEvents: 'input change' }
JS object with options to be passed to FORM.isValidField() method.
See FormJS for details.
In particular, "validateOnEvents" is used inside SurveyJS to validate the fields on those events.
true
wether or not to load the field error message inside the HTML ( shown on failed field validation )
see 'Templates' section below
HTML string to be used as field error container ( when showing an error message on failed field validation )
see 'Templates' section below
HTML string to be used as question (and answers) container when generating the survey
depends on lang setting (see description)
HTML container and text for the loading box (used when requesting the survey JSON file)
depends on lang setting (see description)
Used if an option with empty id is NOT found in the JSON
depends on lang setting (see description)
depends on lang setting (see description)
this text can be used for quesions that let the user choose more than one answer (checkboxes)
Depends on lang setting (see description)
text to show on generic field error validation.
Depends on lang setting (see description)
text to show on error validation of checkboxes with multiple choice.
{{maxChoiceNum}} is mandatory.
Here an example of custom initialization:
SURVEY.setup({ setJSONurl: 'json/survey.json', onInitSuccess: function( json, $surveyForm ){ var $surveyBody = $surveyForm.find('.survey-body'), initResult = json.result; if( initResult === 'OK' ){ $('.stackSlider').stackslider({ piles : false }); } else { $surveyForm.find('.survey-footer').remove(); if ( initResult === 'KO' ){ $surveyBody.html( '<div class="survey-message">Errore durante il caricamento. Per favore, ricarica la pagina.</div>' ); } else if( initResult === 'DONE' ) { $surveyBody.html( '<div class="survey-message">Hai già completato il questionario.</div>' ); } else { console.log('onInitSuccess -> json.result is ', initResult); } } }, onInitError: function( jqXHR, textStatus, errorThrown, $surveyForm ){ $surveyForm.find('.survey-loading').html( '<div class="survey-message">Errore durante il caricamento. Per favore, ricarica la pagina.</div>' ); }, onValidation: function( data ){ // SCROLL THE PAGE TO THE FIRST UNANSWERED QUESTION if( data.event === 'submit' ){ for( var f=0; f<data.fields.length; f++ ){ var obj = data.fields[f]; if( !obj.result ){ var $box = obj.field.closest('[data-formjs-question]'); $('html, body').animate({ scrollTop: $box.offset().top }, 400); break; } } } }, beforeSend: function( JSON, $surveyForm ){ // USED TO ADD/REMOVE/EDIT ELEMENTS OF THE JSON THAT WILL BE SENT return ''; }, onSubmitSuccess: function( json, $surveyForm ){ if( json.result === 'OK' ){ // REMOVE THE SURVEY FORM FROM THE PAGE AND PRINT A RESPONSE MESSAGE $surveyForm.parent().html( '<div class="alert alert-success" role="alert"><p><i class="glyphicon glyphicon-thumbs-up"></i> Great! You completed the mission.</p></div>' ); // OPEN THE BOOTSTRAP MODAL TO SHOW A CONGRATULATION MESSAGE $('#modal-notification').modal('show'); } else { // PRINT THE ERROR MESSAGE AFTER THE FORM $surveyForm.closest('.survey-cont').append( '<div class="alert alert-danger" role="alert"><p><i class="glyphicon glyphicon-exclamation-sign"></i> Generic error, please retry.</p></div>' ); } }, onSubmitError: function( jqXHR, textStatus, errorThrown, $surveyForm ){ // PRINT THE ERROR MESSAGE AFTER THE FORM $surveyForm.closest('.survey-cont').append( '<div class="alert alert-danger" role="alert"><p><i class="glyphicon glyphicon-exclamation-sign"></i> Generic error, please retry.</p></div>' ); } });
You can add a new language ( or override an existing one ), with SURVEY.addLanguage( langString, langMessages )
.
This will also set the language used for the survey.
You MUST pass all the pairs key/value as shown below:
var newLang = { loadingBox: '<div class="survey-loading" data-surveyjs-loading><i class="glyphicon glyphicon-refresh icon-spin"></i> Wird geladen...</div>', selectFirstOption: 'Wähle eine Antwort...', textareaPlaceholder:'Schreibe eine Antwort...', maxChoiceText: 'ANTWORTEN MAX', fieldErrorMessage: 'Du musst antworten', fieldErrorMessageMultiChoice: 'Sie Können bis zu {{maxChoiceNum}} Antworten auswählen.' }; SURVEY.addLanguage( 'de', newLang );
You can initialize the survey with your custom HTML templates for:
Remember to use ALL the data-* attributes and placeholders with the curly braces, for example {{questionId}}, in your custom code.
Here some examples of initialization with custom templates ( these are, actually, the basic templates ):
Custom Template for Fields Error
SURVEY.setup({ setJSONurl: 'json/survey.json', fieldErrorTemplate: '<div class="field-error-message">{{fieldErrorMessage}}</div>'; });
Custom Template for Loading Box
SURVEY.setup({ setJSONurl: 'json/survey.json', loadingBox: '<div class="survey-loading" data-surveyjs-loading><i class="glyphicon glyphicon-refresh icon-spin"></i> Loading...</div>'; });
Custom Template for Questions
SURVEY.setup({ setJSONurl: 'json/survey.json', questionTemplate: '<div data-question-id="{{questionId}}" data-question-index="{{questionNumber}}" data-formjs-question="" class="question-box clearfix" {{maxChoice}}>'+ '<div class="question-header">Question {{questionNumber}}</div>'+ '<div class="question-body">'+ '<div class="question-text">{{questionText}}</div>'+ '<div class="answers-box form-group clearfix">'+ '{{answersHtml}}'+ '</div>'+ '</div>'+ '</div>'; });
Custom Template for Label Tags
SURVEY.setup({ setJSONurl: 'json/survey.json', labelTagCode: '<label for="{{answerCode}}">{{answerString}}</label>', });
Custom Template for Textareas
SURVEY.setup({ setJSONurl: 'json/survey.json', textareaTemplate: '<div class="row">'+ '<div class="col-xs-12 textarea-box">'+ '<textarea id="{{answerCode}}" data-answer-id="{{answerId}}" {{nestedAnswer}} name="user-text-answer-{{questionNumber}}" {{attrRequired}} class="form-control" maxlength="250" rows="6" placeholder="{{placeholder}}"></textarea>'+ '</div>'+ '</div>'; });
Custom Template for Select Tags
SURVEY.setup({ setJSONurl: 'json/survey.json', selectTagCode: '<select id="{{answerCode}}" name="survey-answer-{{questionNumber}}{{addMoreName}}" class="{{fieldClass}}" {{attrRequired}} {{nestedAnswer}} data-answer-root="{{progIdsJoined}}" {{attrRequiredFrom}}>'+ '{{optionsHtml}}'+ '</select>'; });
Custom Template for Selects
SURVEY.setup({ setJSONurl: 'json/survey.json', selectTemplate: '<div class="single-answer" data-answer-index="{{answerIndex}}">'+ '{{selectTagCode}}'+ '</div>'; });
Custom Template for Input Tags
SURVEY.setup({ setJSONurl: 'json/survey.json', inputTagCode: '<input type="{{answerType}}" name="survey-answer-{{questionNumber}}{{addMoreName}}" class="{{fieldClass}}" id="{{answerCode}}" {{nestedAnswer}} data-answer-root="{{progIdsJoined}}" data-answer-id="{{answerId}}" value="{{answerIdValue}}" {{attrRequired}} {{attrRequiredFrom}}/>'; });
Custom Template for Inputs
SURVEY.setup({ setJSONurl: 'json/survey.json', inputTemplate: '<div class="single-answer input-container {{answerType}}" data-answer-index="{{answerIndex}}">'+ '{{inputLabelTagCode}}'+ '</div>'; });
Custom Template for Input Groups
SURVEY.setup({ setJSONurl: 'json/survey.json', inputGroupTemplate: '<div class="single-answer input-group" data-answer-index="{{answerIndex}}">'+ '<span class="input-group-addon {{inputTypeClass}}">'+ '<input id="{{answerCode}}" type="{{answerType}}" data-answer-id="{{answerId}}" name="survey-answer-{{questionNumber}}" value="{{answerIdValue}}" {{attrRequired}} data-require-more=""/>'+ '<label for="{{answerCode}}"> {{answerString}}</label>'+ '</span>'+ '{{relatedAnswerField}}'+ '</div>'; });