Use select lists for multiple choice answers

This commit is contained in:
Joe Fiorini
2015-08-06 10:27:29 -04:00
parent e8c0e68789
commit dd143c1c71
13 changed files with 234 additions and 47 deletions

View File

@@ -507,14 +507,14 @@ function($compile, Rest, GetBasePath, TextareaResize,CreateDialog, GenerateForm,
url = params.url,
callback=params.callback,
scope = params.scope,
i, j,
i,
requiredAsterisk,
requiredClasses,
defaultValue,
choices,
element,
minlength, maxlength,
checked, min, max,
min, max,
survey_url = GetBasePath('job_templates') + id + '/survey_spec/' ;
//for toggling the input on password inputs
@@ -605,41 +605,35 @@ function($compile, Rest, GetBasePath, TextareaResize,CreateDialog, GenerateForm,
if(question.type === 'multiplechoice'){
choices = question.choices.split(/\n/);
element = (question.type==="multiselect") ? "checkbox" : 'radio';
question.default = (question.default) ? question.default : (question.default_multiselect) ? question.default_multiselect : "" ;
html+='<div class="survey_taker_input" > ';
for( j = 0; j<choices.length; j++){
checked = (!Empty(question.default) && question.default.indexOf(choices[j])!==-1) ? "checked" : "";
choices[j] = $filter('sanitize')(choices[j]);
html+= '<input type="'+element+'" class="mc" ng-model="'+question.variable+'" ng-required="'+question.required+'" name="'+question.variable+ ' " id="'+question.variable+'" value=" '+choices[j]+' " '+checked+' >' +
'<span>'+choices[j] +'</span><br>' ;
if (question.default) {
scope[question.variable] = question.default;
} else {
scope[question.variable] = '';
}
html+= '<div class="error survey_error" ng-show="job_launch_form.'+ question.variable + '.$dirty && ' +
'job_launch_form.'+question.variable+'.$error.required\">Please select an answer.</div>'+
'<div class=\"error api-error\" ng-bind=\"" + fld + "_api_error\"></div>';
html+='<div class="survey_taker_input" > ';
html += '<survey-question type="' + question.type + '" index="' + question.index + '" survey-questions="survey_questions" ng-model="' + question.variable + '" ng-required="' + question.required + '"></survey-question>';
// html+= '<div class="error survey_error" ng-show="job_launch_form.'+ question.variable + '.$dirty && ' +
// 'job_launch_form.'+question.variable+'.$error.required\">Please select an answer.</div>'+
// '<div class=\"error api-error\" ng-bind=\"" + fld + "_api_error\"></div>';
html+= '</div>'; //end survey_taker_input
}
if(question.type === "multiselect"){
//seperate the choices out into an array
choices = question.choices.split(/\n/);
question.default = (question.default) ? question.default : (question.default_multiselect) ? question.default_multiselect : "" ;
//ensure that the default answers are in an array
scope[question.variable] = question.default.split(/\n/);
//create a new object to be used by the surveyCheckboxes directive
scope[question.variable + '_object'] = {
name: question.variable,
value: (question.default.split(/\n/)[0]==="") ? [] : question.default.split(/\n/) ,
required: question.required,
options:[]
};
//load the options into the 'options' key of the new object
for(j=0; j<choices.length; j++){
scope[question.variable+'_object'].options.push( {value:choices[j]} );
if (question.default) {
scope[question.variable] = question.default.split(/\n/);
} else {
scope[question.variable] = '';
}
//surveyCheckboxes takes a list of checkboxes and connects them to one scope variable
html += '<survey-checkboxes name="'+question.variable+'" ng-model=" '+question.variable + '_object " ng-required="'+question.required+'">'+
'</survey-checkboxes>{{job_launch_form.'+question.variable+'_object.$error.checkbox}}'+
'<div class="error survey_error" ng-show="job_launch_form.'+question.variable+'.$error.checkbox">Please select at least one answer.</div>';
//create a new object to be used by the surveyCheckboxes directive
html += '<survey-question type="' + question.type + '" index="' + question.index + '" survey-questions="survey_questions" ng-model="' + question.variable + '" ng-required="' + question.required + '"></survey-question>';
// html += '<survey-checkboxes name="'+question.variable+'" ng-model=" '+question.variable + '_object " ng-required="'+question.required+'">'+
// '</survey-checkboxes>{{job_launch_form.'+question.variable+'_object.$error.checkbox}}'+
// '<div class="error survey_error" ng-show="job_launch_form.'+question.variable+'.$error.checkbox">Please select at least one answer.</div>';
}
if(question.type === 'integer'){

View File

@@ -1,6 +1,7 @@
import listGenerator from '../../shared/list-generator/main';
import questions from './questions/main';
import surveys from './surveys/main';
import render from './render/main';
import shared from './shared/main';
export default
@@ -8,5 +9,6 @@ export default
[ listGenerator.name,
questions.name,
surveys.name,
render.name,
shared.name
]);

View File

@@ -18,13 +18,9 @@ export default
index = params.index,
required,
element,
choices,
i,
checked,
max,
min,
defaultValue,
answers,
html = "";
question.index = index;
@@ -65,18 +61,28 @@ export default
'</div></div>';
}
if(question.type === 'multiplechoice' || question.type === "multiselect"){
choices = question.choices.split(/\n/);
element = (question.type==="multiselect") ? "checkbox" : 'radio';
question.default = (question.default) ? question.default : (question.default_multiselect) ? question.default_multiselect : "" ;
answers = question.default.split(/\n/);
html += '<div class="input_area">';
for( i = 0; i<choices.length; i++){
checked = (!Empty(question.default) && $.inArray(choices[i], answers) !== -1) ? "checked" : "";
choices[i] = $filter('sanitize')(choices[i]);
choices[i] = scope.serialize(choices[i]);
html+= '<input type="'+element+'" class="mc" ng-required="!'+question.variable+'" name="'+question.variable+ ' " id="'+question.variable+'" value=" '+choices[i]+' " '+checked+' disabled>' +
'<span>'+choices[i] +'</span><br>' ;
question.default = question.default_multiselect || question.default;
var defaultScopePropertyName =
question.variable + '_default';
if (question.default) {
if (question.type === 'multiselect' && typeof question.default.split === 'function') {
scope[defaultScopePropertyName] = question.default.split('\n');
} else if (question.type !== 'multiselect') {
scope[defaultScopePropertyName] = question.default;
}
} else {
scope[defaultScopePropertyName] = '';
}
html += '<div class="row">';
html += '<div class="col-xs-8">';
html += '<div class="SurveyControls-selectWrapper">';
html += '<survey-question type="' + question.type + '" index="' + question.index + '" survey-questions="survey_questions" ng-required="' + question.required + '" ng-model="' + defaultScopePropertyName + '"></survey-question>';
html += '</div>';
html += '</div>';
html += '</div>';
}

View File

@@ -0,0 +1,9 @@
import surveyQuestion from './survey-question.directive';
import multipleChoice from './multiple-choice.directive';
import multiSelect from './multiselect.directive';
export default
angular.module('jobTemplates.surveyMaker.render', [])
.directive('surveyQuestion', surveyQuestion)
.directive('multipleChoice', multipleChoice)
.directive('multiSelect', multiSelect);

View File

@@ -0,0 +1,56 @@
/* jshint unused: vars */
import {templateUrl} from '../../../shared/template-url/template-url.factory';
function link($timeout, scope, element, attrs, ngModel) {
attrs.width = attrs.width || '100%';
$timeout(function() {
$.fn.select2.amd.require(
[ 'select2/utils',
'select2/dropdown',
'select2/dropdown/search',
'select2/dropdown/attachContainer',
'select2/dropdown/closeOnSelect',
'select2/dropdown/minimumResultsForSearch'
],
function(Utils, Dropdown, Search, AttachContainer, CloseOnSelect, MinimumResultsForSearch) {
var CustomAdapter =
_.reduce([Search, AttachContainer, CloseOnSelect, MinimumResultsForSearch],
function(Adapter, Decorator) {
return Utils.Decorate(Adapter, Decorator);
}, Dropdown);
element.find('select').select2(
{ multiple: scope.isMultipleSelect(),
minimumResultsForSearch: Infinity,
theme: 'bootstrap',
width: attrs.width,
dropdownAdapter: CustomAdapter
});
});
});
}
export default
[ '$timeout',
function($timeout) {
var directive =
{ restrict: 'E',
require: 'ngModel',
scope: {
isMultipleSelect: '&multiSelect',
choices: '=',
question: '=',
isRequired: '=ngRequired',
selectedValue: '=ngModel'
},
templateUrl: templateUrl('job-templates/survey-maker/render/multiple-choice'),
link: _.partial(link, $timeout)
};
return directive;
}
];

View File

@@ -0,0 +1,5 @@
<div>
<select class="form-control" ng-model="selectedValue" multi-select ng-required="isRequired">
<option ng-repeat="choice in choices" value="{{choice}}" ng-selected="selectedValue.indexOf(choice) !== -1">{{choice}}</option>
</select>
</div>

View File

@@ -0,0 +1,42 @@
/* jshint unused: vars */
/**
* @ngdoc
*
* @name jobTemplates.surveyMaker.render.multiSelect
* @description
* Angular provides no method of binding to "multiple" for
* select lists. This is because under normal circumstances,
* the structure of `ng-model` changes based on whether `multiple`
* is true or false. We're not needing to "bind" to "multiple",
* but we do need to pass in the value dynamically. This allows
* us to do that.
*/
var directive =
{ require: 'ngModel',
compile: function() {
return {
pre: function(scope, element, attrs, ngModel) {
if (_.isUndefined(scope.isMultipleSelect)) {
return;
}
if (!scope.isMultipleSelect()) {
return;
}
element.attr('multiple', true);
attrs.multiple = true;
}
};
},
priority: 1000
};
export default
function() {
return directive;
}

View File

@@ -0,0 +1,50 @@
/* jshint unused: vars */
import {templateUrl} from '../../../shared/template-url/template-url.factory';
/**
* @ngdoc
* @name jobTemplates.surveyMaker.render.surveyQuestion
* @description
* Directive that will eventually hold all logic
* for rendering different form controls based on
* the question type for a survey.
*/
// Since we're generating HTML for the entire survey, and _then_
// calling $compile, this directive never actually gets compiled
// with the question object we need. Therefore, we give it the index
// of the question as an attribute (not scope) and then look it up
// in the `survey_questions` by that index when it the directive gets
// compiled.
//
function findQuestionByIndex(questions, index) {
return _.find(questions, function(question) {
return question.index === index;
});
}
function link(scope, element, attrs) {
var question = findQuestionByIndex(scope.surveyQuestions, Number(attrs.index));
scope.question = question;
if (!_.isUndefined(question.choices)) {
scope.choices = question.choices.split('\n');
}
}
export default
function() {
var directive =
{ restrict: 'E',
scope:
{ surveyQuestions: '=',
selectedValue: '=ngModel',
isRequired: '@ngRequired'
},
templateUrl: templateUrl('job-templates/survey-maker/render/survey-question'),
link: link
};
return directive;
}

View File

@@ -0,0 +1,7 @@
<multiple-choice
multi-select="question.type === 'multiselect'"
question="question"
choices="choices"
ng-required="isRequired === 'true'"
ng-model="selectedValue">
</multiple-choice>

View File

@@ -0,0 +1,11 @@
/** @define SurveyControls */
.SurveyControls {
&-selectWrapper {
margin-left: 15px;
}
&--dropdown {
z-index: 10000;
opacity: 1;
}
}

View File

@@ -136,13 +136,13 @@ export default
if(questions.length>0){
$('#survey-save-button').removeAttr('disabled');
}
scope.finalizeQuestion(questions[key], key);
scope.finalizeQuestion(questions[key], Number(key));
}
else if(scope.mode=== 'edit' ){
if(scope.survey_questions.length>0 && scope.can_edit === true){
$('#survey-save-button').removeAttr('disabled');
}
scope.finalizeQuestion(scope.survey_questions[key] , key);
scope.finalizeQuestion(scope.survey_questions[key] , Number(key));
}
}
};
@@ -464,7 +464,7 @@ export default
scope.survey_questions[key] = data;
}
$('#'+elementID).empty();
scope.finalizeQuestion(data , key);
scope.finalizeQuestion(data , Number(key));
}

View File

@@ -70,6 +70,9 @@ export default
}
},
_allowInteraction: function(e) {
return !!$(e.target).is('.select2-input') || this._super(e);
},
callback: callback
});
};

View File

@@ -55,6 +55,7 @@ angular.module('ModalDialog', ['Utilities', 'ParseHelper'])
onResizeStop = params.onResizeStop,
onClose = params.onClose,
onOpen = params.onOpen,
_allowInteraction = params._allowInteraction,
callback = params.callback,
beforeDestroy = params.beforeDestroy,
closeOnEscape = (params.closeOnEscape === undefined) ? false : params.closeOnEscape,
@@ -177,7 +178,8 @@ angular.module('ModalDialog', ['Utilities', 'ParseHelper'])
if (onOpen) {
onOpen();
}
}
},
_allowInteraction: _allowInteraction
});
};
}])