SenseNet Survey Editor for developers

From Sense/Net Wiki
Jump to: navigation, search
  •  
  •  
  •  
  •  
  • 100%
  • 6.5.5
  • Enterprise
  • Community
  • Planned

Overview

Survey Editor
Survey Editor is a tool to help users creating and managing surveys without coding. It is actually a jQuery plugin which can be attached to a List-based Content and manipulate with its Fields. Editing, modifying and browsing the Survey is based on Sense/Net Content Views, and the Field manipulation is working through Sense/Net OData REST API.

SurveyList ContentType

SurveyList is a new Content Type derived from List because in this case we will use the expando fields to add, modify and delete Questions. There're three new related OData action, for further information please check this article. The expando fields will be actually added to the SurveyLists children items and because we have to create this children item a special way (the Survey Editors browse mode will render the form to fill out) we've created a new Content Type for the children items to. This new type is the SurveyListItem.

Store Survey's Data

The SurveyList type has some common and some special Fields that we need to use the Survey Editor. Besides DisplayName and Description it has three additional LongText fields one for the intro text, on for the outro text of the Survey and one for store the Survey structure in JSON. When a user creates or modifies a Survey this Fields are changing in the background and when the user saves the Survey actually this Fields value will be saved on the Survey Content.

Store Questions

As it is mentioned above the questions are actually expando fields on a list. So if a user add a new question to the Survey first the new question is added to the JSON structure and marked as new. When the user saves the Survey the marked questions will be saved on the SurveyList as Fields with all the possible validation and other settings.

Getting started

The Survey has three modes/Content Views as other ContentTypes but it means in this case that the SurveyList Content Type has an InlineNew.ascx and an InlineEdit.ascx for adding and editing a survey and the SurveyListItem has an InlineNew.ascx to display the survey for end-users to fill-out the form (and actually create a new SurveyListItem).

The Survey plugin should be bound to an html container element just like other jQuery plugins.

<div id=”surveyContainer” data-view="edit"></div>

It is important to set the view mode in the data-view attribute that can have three values: new, edit and browse just the same as in the case of Content Views. Because we use the same plugin in all the three modes the plugin has to know about the current view to render to questions in the appropriate way and bind all the needed functionality.

     var survey = $('#surveyContainer').Survey({ 
        path: currentListPath, 
        title: $('.sn-ctrl-displayname'), 
        description: $('.sn-ctrl-description'), 
        structure: $('.sn-ctrl-rawjson'), 
        intro: $('.sn-ctrl-intro'), 
        outro: $('.sn-ctrl-outro') 
    });


Configuring the Survey Editor jQuery plugin

path string (default: null)

Path of the Survey (current List).

title object (default: null)

It should be a jQuery object, the input which will store the title (DisplayName) of the Survey content.

description object (default: null)

It should be a jQuery object, the input which will store the description of the Survey content.

structure object (default: null)

It should be a jQuery object, the input which will store the Survey's section and field structure in JSON.

intro object (default: null)

It should be a jQuery object, the input which could store the intro text of the Survey.

outro object (default: null)

It should be a jQuery object, the input which could store the outro text of the Survey.

Most of these jQuery objects represent Fields in the background. Since we're using common Sense/Net Content Views to display the Survey content we have to reach (read and write) these fields are hidden and connected to the plugin through this plugin configurations.


Methods

Some of the plugin methods can be called outside a plugin (e.g. from a Field js) to get question or section parameters or execute a function on a question or section. First of all if you want to use one of them, you have to get the Survey object itself in the following way:

var survey = $('#surveyContainer').data('Survey');

Then you will be able to reach the following methods:

init

Initializes the Survey.

survey.init();


initEditor

Initializes the Survey in Edit mode.

survey.initEditor();


initSurvey

Initializes the Survey in Browse mode.

survey.initSurvey();


initSurveySettings

Initializes the default Fields of the Survey (DisplayName, Description, etc).

survey.initSurveySettings();


renderSurveySection

Renders a Survey section by the given section object and section id which represents the last section.

survey.renderSurveySection(section, lastSectionId);


renderSurveyQuestion

Renders a Survey question by the given section jQuery object and a question object.

survey.renderSurveyQuestion($section, question);


initMenu

Initializes the a Survey menu that let you add new sections to the Survey.


survey.initMenu();


initProgressbar

Initializes the a Survey's progressbar.

survey.initProgressbar();


toggleSection

Lets you to open and close a section by its Id.

survey.toggleSection(sectionId);


getContainer

Gets the container DOM element of the viewer.

viewer = $dv.data('snDocViewer');
var $container = viewer.getContainer();


deleteSection

Deletes a section by its Id. It can have an optional callback parameters, so you the Survey editor can execute an additional function after the section is deleted.

survey.deleteSection(sectionId, myCallback());


addNewSection

Creates a new section after the last one.

survey.addNewSection();


selectSection

Sets a section selected by its Id (section get a new class and the page is scrolled to the selected section).

survey.selectSection(sectionId);


goToSection

The Survey jumps to a section by a given current section object and an optional boolean parameter (true if you want go to the next section false if you want to back. If there's no second parameter the survey will go to the given section).

survey.goToSection($currentSection, true);


scrollToSection

Page scrolls to a section by the given section Id.

survey.scrollToSection(sectionId);


addQuestionToSection

Adds a question to a section by a section Id and a question type string. With only two parameters an new question is added with its default values. If you want to add an exisiting question to a section you can add it as a third parameter of this method.

survey.scrollToSection(sectionId, type);

Or

survey.scrollToSection(sectionId, type, question);


selectQuestion

Sets a question selected by its Id (question's editor part will be open and displayed).

survey.selectQuestion(sectionId);


saveQuestion

Saves a question a given question to a section by a sectionId. Optional third parameter could be a callback function.

survey.saveQuestion(sectionId,question,myCallback());


modifyQuestion

Changes a question in the structure JSON by the given question object, a sectionId and the affected question's jQuery object. Last one is important because we have to mark the changed elements so if we save the Survey we will know which field's attributes have to be saved.

survey.modifyQuestion(question,sectionId,$('#myQuestion'));


deleteQuestion

Deletes a question by a given section Id and question Id.

survey.deleteQuestion(sectionId,questionId);


saveSurvey

Saves the new survey with all sections and questions. Since we use List based ContentType the Survey and its questions (Fields) are saved sequentially one by one.

survey.saveSurvey();


modifySurvey

Saves the modified survey with all modified sections and questions. Since we use List based ContentType the Survey and its questions (Fields) are saved sequentially one by one. Only those things are send to the server which are changed or new.

survey.modifySurvey();


getModifiedQuestions

Returns an array with the modified question objects.

survey.getModifiedQuestions();


getModifiedSections

survey.getModifiedSections();

survey.getModifiedSections();


getSections

Returns the Sections array.

survey.getSections();


getSectionById

Returns a section object by a given section Id.

  Returns a section object by a given section Id.


getQuestionById

Returns a question object by a given section Id and question Id.

   survey.getQuestionById('528ecc87','2c4a3be2');


getSectionByElement

Returns a section object by a given section element (jQuery object).

   survey.getSectionByElement($('#mySection'));


getQuestionByElement

Returns a question object by a given question element (jQuery object).

survey.getQuestionByElement($('#myQuestion'));


saveDataToTextbox

Convert the JSON structure to string and put it to the given input in the background;

survey.saveDataToTextbox();


refreshPreview

Refreshes the preview part of a given question by question Id, a template, a question and a rendering function. The latter one is optional and need to be added if you know that the question (Field) has a custom rendering method.

survey.refreshPreview(questionId,template,question,myRenderingFunction());


getValidator

Returns the survey's validator object.

survey.getValidator();


Validation

Validation schema

All types of questions (Fields) can have their own validation types, rules, error messages, etc. This validation related things can be defined in the Fields validation schema.

SN.Fields.Number = { 
… 
  editor: { 
     schema: { 
        … 
        validation: { 
            Type: [ 
               name: 'number', 
               text: 'Number', 
               defaultValue: 'Number', 
               snFieldType: 'Number', 
               rules: [ 
                  { 
                      name: 'maxvalue', 
                      text: 'Less than', 
                      snField: 'MaxValue', 
                      type: 'number', 
                      value: true, 
                      method: function(e){ 
                          var validate = e.data('maxvalue'); 
                          if (typeof validate !== 'undefined'  
                              && validate !== false) { 
                                var value = e.val(); 
                                if (value === '') 
                                  return true; 
                                else { 
                                  var value = Number(e.val()); 
                                  var maxvalue =  
                                     Number(e.attr('data-maxvalue-value')); 
                                  return (value < maxvalue); 
                                            } 
                                        } 
                           return true; 
                      }  
                  }]  
            ] 
        }} 
  }}

There should be an array with the validation types (text, number, etc), this types will be listed and can be chosen as options in the first dropdown of the validation row.


Choosing validation type


After choosing one of the options the second dropdown will be filled with the related rules (which are defined under the chosen type in the validation schema). If you don't need to define types only rules, create only one Type object and the Editor will know that you want to display only one dropdown with the rules. Types can be related with actual Sense/Net fields (e.g. the Short answer could be saved as a ShortText or as a Number based on the chosen validation type) so if you want to use that feature define the related Field name in Type's snField property, if it's not necessary leave this property out. Rule objects are defined in an array under the Type objects and will be listed in the second dropdown in the validation row of a question.


Choosing validation rule


The 'name' property is the identifier of the rule, and because it will be saved in the kendoui validation object must be unique. (Please, check the default kendoui validation rules because they cannot be overridden, so if you create a rule with the name 'max', it will not be used because of the validation rule in kendoui with the same name.) If the rule is related to a Sense/Net FieldSetting, it can be save on the field in the background so that it is possible to validate a question both client and server side. The first textbox will be rendered based on the chosen rule and it will contain the value with which the user-defined answer will be compared and validated. It is possible to display and use two or more inputs in case of value ranges (e.g. 'Between') with defining the snField as an array:

… 
snField: ['MinValue', 'MaxValue'] 
...

All of the rules must have a method parameter with a function which will be executed when the related answer is validated.

Saving validation definition on a question

The validation definition is saved on every question based on the validation type, rule, value and error message that are set on the question in the validation row. The schema of the saved validation object is defined in the field section of the editor schema as a property object.

Validation: { 
       Type: { type: "dropdown", index: 0 }, 
       Rule: { type: "dropdown", cascadeFrom: 'Type', index: 1 }, 
       Value: { type: "string", index: 2 }, 
       ErrorMessage: { type: "string", index: 3, placeHolder: "Default error message!" } 
}

If you set a value of one of the dropdowns or textboxes the related property of the validation object gets a 'value' property with the value that you've set.

If you use a question type which is related to a FieldSetting content (Number, DateTime, etc.) it is possible to save the related (e.g. MinValue, MaxValue, etc) settings also on the content itself.

Validation process

Sense/Net Survey question validation is based on KendoUI's validation. All the saved validation rules are grouped in a validation object and the related inputs or even entire questions get the appropriate validation rules, values and error message as attributes.

<input type="number" id="2b93a9f5" name="2b93a9f5" class="sn-answer k-invalid"  required="required" validationmessage="Required question" data-validate data-maxvalue data-maxvalue-value="10" data-maxvalue-msg="Must be greater than 10!" >

Validation is executed on every question one by one when the user try to navigate to the next page or try to submit the form. The related method is executed also when a value of an input is changed so the user gets immediate feedback. You can learn more about KendoUI validatior [[3]]. And check this very informative and useful [[4]] about extending KendoUI validator with custom rules.

Validating required questions

Validation of required fields works the same as validation on other fields but it's saved and stored separately. All the questions (fields) have a property named 'Required' that can be set to true or false. If a question is set to required on the UI the true value is set on the Required property.


Required question


{   
   "Type":"ShortText", 
   "Control":"ShortAnswer", 
   "Id":"ee9d6631", 
   "Title":"Untitled question", 
   "Hint":"", 
   "PlaceHolder":"", 
   "Required":true, 
   "Validation":{}

Custom requirements

In special cases when you want to validate required field you need more than check if the input is empty or not. It is possible to add a custom, complex requirement validation that fit your needs (e.g. you have a grid-form question and want to check if there's minimum one answer per row). Two changes should be made in the question schema. You have to add a property names CustomRequired, which have to contain the reference to the method which have to be executed on validation as default value.

... 
Hint: { type: "string" }, 
Required: { type: "boolean", defaultValue: false }, 
CustomRequired: {type: "string", defaultValue: "grid-required"} 
...

And you have to define the validation method itself in the same form and place where the other validation rules are with the name that you've added in the defaultValue parameter of CustomRequired. Because it is requirement check it cannot be changed on the UI so have to be set and saved when a new empty question is added to the survey. Add the name of your custom method as the 'value' parameters value in Validation.Rule.

Validation: { 
    Type: { type: "dropdown", index: 0, value: 'text' }, 
    Rule: { type: "dropdown", cascadeFrom: 'Type', index: 1, value: 'grid-required' }, 
    Value: { type: "string", index: 2 }, 
    ErrorMessage: { type: "string", index: 3, value: 'error!!!' } 
}


Templating

Survey Section and Question templating is based on Kendo UI templating. You can define separate templates for the edit and browse views in the appropriate part of the question/field describing JSON schema:

SN.Fields.Grid = { 
      … 
      editor: { 
             schema:{}, 
             template: '<div class="sn-survey-question sn-survey-question-#=Type#" id="#=Id #">…</div>' 
      }, 
      fill: { 
             template: '...', 
             ... 
      } 
}

Please use SenseNet Html templates instead of putting hard-coded html fragments in your plugin.

Settings

In some cases you need to add customizable settings to a question type when a user have to set basic question related stuff like adding new columns in a grid question or new options in a choice type question. You're able to add additional savable fields, a template and a rendering method too, so you can add and display fully custom data and editor functionality to a question.

SN.Fields.Grid = { 
    … 
    editor: { 
        schema: { 
            fields: { 
                 … 
                 GridSchema: {...} 
                 Settings: { 
                        template: '<table class="sn-survey-gridquestion-table"></table>', 
                        render: function($question, view){...} 
                 } 
            }   
        } 
    } 
    ... 
}


Grid question


Custom rendering

You can add custom additional functionality to your question/field type at the settings and the fill part of the JSON structure. The one that you add into the Settings part will be executed when a new question is added with the type to the Survey. You get the current question as a jQuery object as the argument of your function so you can reach and use the container item and so the related question also. The render method of the 'fill' part is to add custom functionality in browse view, for example define on what event should the question be validated.


Saving custom value

If you use custom question types which are related to Sense/Net Fields like Number or DateTime the user fills the input and the inputs value is saved on the SurveyItem content as a value of the appropriate field. But there're question types which have a more complex structure to save like the grid or upload types. So in this cases you have to define a 'value' param in the fill part of the JSON which should be a function that returns the savable value as a string (e.g. in the case of the grid question type it is a json converted to string with the columns and rows and in the case of the upload question type it is a list of paths).


Question types in Sense/Net Survey

  • Short answer
  • Number
  • Whole number
  • Paragraph
  • Date and time
  • Switch
  • Slider
  • Radiobutton
  • Dropdown
  • Checkbox
  • Grid
  • Fileupload
  • Optional text

If you want to develop a custom question type check How to create a custom question-type to the survey: Optional Text question


Related links