Augmenting default questions

Overview

If you need to change or extend some aspects of client-side behavior of default questions you can use custom views. Supports wide variety of scenarios.
We use a naming convention to distinguish between public and private methods and properties, use of private methods and properties is not supported. Methods and properties names starting with “_” are private and may be changed at any time without warning which could lead to unexpected behaviour or could prevent your survey from working.

API spec

window.Confirmit.pageView = {
    // dictionary of default question view types, could be used inherit own classes from them or override pieces of functionality using prototypes
    guestionViewTypes: {
        "SingleQuestionView": <function>,
        "MultiQuestionView": <function>,
        ...
    },

    // question view factory used by presentation layer to build views
    // initialized with default factory instance, can be replaced with a custom one
    questionViewFactory: {
        create: function (model) { ... }
    },

    // helper method to use custom question view for a specific question only (could be useful when invoked from question/skin scripts)
    registerCustomQuestionView: function (questionId, createViewFn) { ... }
}

Examples

Question level

Use the default view type, override on an instance (common use: minor tweak for a specific question)

/* typically done in a question or skin script */


var createFn = function (model) {
      var factory = Confirmit.pageView.questionViewFactory;
    var view = factory.create(model);

    view._showErrors = function () { ... }; // make this specific instance to behave in a different way
    return view;
};
Confirmit.pageView.registerCustomQuestionView(currentQuestion.id, createFn);

Question type level

Override on a type (common use: minor tweak for all question views of a certain type)

/* typically done in a theme script */


// grab default view type currently in use
var SingleView = Confirmit.pageView.questionViewTypes.SingleQuestionView;
// hijack it to make all instances to behave in a different way
SingleView.prototype._showErrors = function () { ... };  

Side by side views

Use custom view types side by side with default ones (common use: fully custom behavior for a bunch of questions, default behavior for the rest - could be controlled by a question skin etc)

// define custom view (typically in a theme script)
var MyCustomView = function (model) { ... }; 
MyCustomView.prototype = { ... };

// apply custom view (typically in skin script)
var createFn = function (model) {
    var view = new MyCustomView(model);
    return view;
};
Confirmit.pageView.registerCustomQuestionView(currentQuestion.id, createFn);

Inherit from default views

Create custom types which inherit from default ones (common use: build custom types on top of existing default ones)

/* typically done in a theme script */


// grab the default view type 
var DefaultSingleView = Confirmit.api.pageView.questionViewTypes["SingleQuestionView"];


// define a constructor for a custom view 
var MyCustomSingleView = function (model) { 
    DefaultSingleView.call(this, model);
    ... 
}; 
// inherit from default view type
MyCustomView.prototype = Object.create(DefaultSingleView.prototype);
MyCustomView.prototype.constructor = MyCustomView;


// implement custom logic on top of it
MyCustomView.prototype._showErrors = function () { ... }; 


/* typically done in a skin script */

// apply custom view
var createFn = function (model) {
    var view = new MyCustomSingleView(model);
    return view;
};
Confirmit.pageView.registerCustomQuestionView(currentQuestion.id, createFn);

Replace default view with custom

Full control over question view creation (common use: build custom type library to re-use in multiple projects)

/* full control over views creation */


// keep ref to default factory, so we can invoke it for non-custom types
var defaultQuestionViewFactory = Confirmit.pageView.questionViewFactory;


// use default types to either override their default dehavior or use for inheritance
var defaultQuestionViewTypes = Confirmit.pageView.questionViewTypes;
// example: we hijack all default geolocation views to use an alternative postion provider
defaultQuestionViewTypes["GeolocationQuestionView"].prototype._getCurrentPosition = function () { ... };


// define own custom views
var MyCustomSingleQuestionView = function (model) { ... };
var MyCustomMultiQuestionView = function (model) { ... };

// define own question view factory to control view creation
var myCustomViewFactory = {
    create: function (model) {
        switch (model.type) {

            // handle custom types
            case 'Single':
                return new MyCustomSingleQuestionView(model);
            case 'Multi':
                return new MyCustomMultiQuestionView(model);

            // use default view, but do something with an instance
            case 'Ranking':
                var view = defaultQuestionViewFactory.create(model);
                if (new Date().getDay() === 2) // Tuesday    
                    view._showErrors = function() { alert('May the Force be with you'); };
                return view;

            // offload the rest to default factory
            default:
                return defaultQuestionViewFactory.create(model);
        }
    }
};

// replace the default factory with the custom one
Confirmit.pageView.questionViewFactory = myCustomViewFactory;

Detach question views

If you want to manually manage resources when working with dynamic questions, you need to override the detach() method in your custom view

var createFn = function (model) {
    var factory = Confirmit.pageView.questionViewFactory;
    var view = factory.create(model);
    view.detach = function () { ... };

    return view;
};
Confirmit.pageView.registerCustomQuestionView(currentQuestion.id, createFn);