got validity working for rating field

This commit is contained in:
David Baldwynn 2017-11-13 21:06:30 -08:00
parent 04001244d1
commit f5e32e9548
16 changed files with 79 additions and 138 deletions

View File

@ -254,9 +254,11 @@ function getDeletedIndexes(needle, haystack){
}
function formFieldsAllHaveIds(form_fields){
for(var i=0; i<form_fields.length; i++){
if(!form_fields[i].hasOwnProperty('_id') && !form_fields[i].hasOwnProperty('globalId')){
return false;
if(form_fields){
for(var i=0; i<form_fields.length; i++){
if(form_fields[i] && !form_fields[i].hasOwnProperty('_id') && !form_fields[i].hasOwnProperty('globalId')){
return false;
}
}
}
return true;

View File

@ -97,7 +97,10 @@ function BaseFieldSchema(){
type: String,
enum: constants.fieldTypes
},
fieldValue: Schema.Types.Mixed
fieldValue: {
type: Schema.Types.Mixed,
default: ''
}
});
this.plugin(timeStampPlugin, {
@ -132,19 +135,14 @@ FormFieldSchema.pre('validate', function(next) {
return(next(error));
}
}else{
} else {
//Setting default values for ratingOptions
if(!this.ratingOptions.steps){
if(!this.ratingOptions.steps) {
this.ratingOptions.steps = 10;
}
if(!this.ratingOptions.shape){
this.ratingOptions.shape = 'Star';
}
//Checking that the fieldValue is between 0 and ratingOptions.steps
if(this.fieldValue+0 > this.ratingOptions.steps || this.fieldValue+0 < 0){
this.fieldValue = 1;
}
}

View File

@ -79,13 +79,11 @@ html(lang='en', xmlns='http://www.w3.org/1999/xhtml')
//Socket.io Client Dependency
script(src='/static/lib/socket.io-client/dist/socket.io.min.js')
//Minified Bower Dependencies
script(src='/static/lib/angular/angular.min.js')
script(src='/static/dist/vendor.min.js')
script(src='/static/lib/angular-ui-date/src/date.js', type='text/javascript')
//Bower JS dependencies
each bowerJSFile in bowerFormJSFiles
script(type='text/javascript', src=bowerJSFile)
// end Bower JS dependencies
script(src='/static/lib/jquery-ui/jquery-ui.js', type='text/javascript')
script(src='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js', integrity='sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa', crossorigin='anonymous')
//Application JavaScript Files
each jsFile in formJSFiles
@ -96,7 +94,7 @@ html(lang='en', xmlns='http://www.w3.org/1999/xhtml')
//Livereload script rendered
script(async='', type='text/javascript', src='http://#{request.hostname}:35729/livereload.js')
script Raven.config('https://825fefd6b4ed4a4da199c1b832ca845c@sentry.tellform.com/2').install();
//script Raven.config('https://825fefd6b4ed4a4da199c1b832ca845c@sentry.tellform.com/2').install();
if google_analytics_id
script window.ga=function(){ga.q.push(arguments)};ga.q=[];ga.l=+new Date;ga('create','{{google_analytics_id}}','auto');ga('send','pageview')

View File

@ -62,6 +62,12 @@ module.exports.removeRootDir = function(files, removeRoot, addRoot) {
/**
* Get the app's bower dependencies
*/
module.exports.getBowerFormJSAssets = function() {
if(process.env.NODE_ENV === 'production'){
return '/static/dist/vendor.min.js'
}
return this.removeRootDir(minBowerFiles('**/**.js'), 'public/', 'static/');
};
module.exports.getBowerJSAssets = function() {
return this.removeRootDir(minBowerFiles('**/**.js'), 'public/', 'static/');
};

View File

@ -30,6 +30,6 @@ module.exports = {
assets: {
css: ['public/dist/application.min.css'],
js: ['public/dist/application.min.js', 'public/dist/populate_template_cache.js'],
form_js: ['public/dist/form-application.min.js', 'public/dist/form_populate_template_cache.js', 'public/dist/form-vendor.min.js']
form_js: ['public/dist/form-application.min.js', 'public/dist/form_populate_template_cache.js']
}
};

View File

@ -78,6 +78,7 @@ module.exports = function(db) {
app.locals.socketUrl = config.socketUrl;
}
app.locals.bowerFormJSFiles = config.getBowerFormJSAssets();
app.locals.bowerJSFiles = config.getBowerJSAssets();
app.locals.bowerCssFiles = config.getBowerCSSAssets();
app.locals.bowerOtherFiles = config.getBowerOtherAssets();

View File

@ -19,7 +19,6 @@ angular.module('view-form').directive('submitFormDirective', ['$http', 'TimeCoun
ispreview: '='
},
controller: function($document, $window, $scope){
var NOSCROLL = false;
var FORM_ACTION_ID = 'submit_field';
$scope.forms = {};
@ -32,12 +31,26 @@ angular.module('view-form').directive('submitFormDirective', ['$http', 'TimeCoun
return field.fieldType !== 'statement';
}).length;
var nb_valid = $filter('formValidity')($scope.myform);
$scope.translateAdvancementData = {
done: nb_valid,
total: form_fields_count,
answers_not_completed: form_fields_count - nb_valid
};
$scope.$watch('myform', function(oldVal, newVal){
$scope.myform.visible_form_fields = $scope.myform.form_fields.filter(function(field){
return !field.deletePreserved;
});
console.log($scope.myform.visible_form_fields);
})
$scope.updateFormValidity = function(){
$timeout(function(){
var nb_valid = $scope.myform.form_fields.filter(function(field){
return (field.fieldType === 'statement' || field.fieldValue !== '' || !field.required);
}).length;
$scope.translateAdvancementData = {
done: nb_valid,
total: $scope.myform.visible_form_fields.length
};
});
}
$scope.updateFormValidity();
$scope.reloadForm = function(){
//Reset Form
@ -135,19 +148,14 @@ angular.module('view-form').directive('submitFormDirective', ['$http', 'TimeCoun
return $scope.selected.index;
};
$scope.isActiveField = function(field){
if($scope.selected._id === field._id) {
return true
}
return false;
};
$scope.setActiveField = $rootScope.setActiveField = function(field_id, field_index, animateScroll) {
if($scope.selected === null || (!field_id && field_index === null) ) {
return;
}
if(!field_id){
if(field_id === FORM_ACTION_ID){
field_index = $scope.myform.visible_form_fields.length;
} else if(!field_id) {
field_id = $scope.myform.visible_form_fields[field_index]._id;
} else if(field_index === null){
field_index = $scope.myform.visible_form_fields.length
@ -168,108 +176,31 @@ angular.module('view-form').directive('submitFormDirective', ['$http', 'TimeCoun
$scope.selected._id = field_id;
$scope.selected.index = field_index;
var nb_valid = $filter('formValidity')($scope.myform);
$scope.translateAdvancementData = {
done: nb_valid,
total: form_fields_count,
answers_not_completed: form_fields_count - nb_valid
};
if(animateScroll){
NOSCROLL=true;
setTimeout(function() {
$document.scrollToElement(angular.element('#'+field_id), -10, 50).then(function() {
NOSCROLL = false;
setTimeout(function() {
if (document.querySelectorAll('#'+field_id+' .focusOn').length) {
//Handle default case
document.querySelectorAll('#'+field_id+' .focusOn')[0].focus();
} else if(document.querySelectorAll('#'+field_id+' input').length) {
//Handle case for rating input
document.querySelectorAll('#'+field_id+' input')[0].focus();
} else {
//Handle case for dropdown input
document.querySelectorAll('#'+field_id+'.selectize-input')[0].focus();
}
});
});
$document.scrollToElement(angular.element('#'+field_id), -10, 50).then(function() {
if (angular.element('#'+field_id+' .focusOn').length) {
//Handle default case
angular.element('#'+field_id+' .focusOn')[0].focus();
} else if(angular.element('#'+field_id+' input').length) {
//Handle case for rating input
angular.element('#'+field_id+' input')[0].focus();
} else {
//Handle case for dropdown input
angular.element('#'+field_id+'.selectize-input')[0].focus();
}
});
}
}
};
$scope.$watch('selected.index', function(oldValue, newValue){
if(oldValue !== newValue && newValue < $scope.myform.form_fields.length){
//Only send analytics data if form has not been submitted
if(!$scope.myform.submitted){
//SendVisitorData.send($scope.myform, newValue, TimeCounter.getTimeElapsed());
}
}
});
$rootScope.$on('duScrollspy:becameActive', function($event, $element, $target){
console.log($element.prop('id'));
$scope.setActiveField($element.prop('id'), null, false);
console.log($scope.selected.index);
$scope.$apply();
$scope.updateFormValidity();
$scope.$apply()
if(!$scope.myform.submitted){
SendVisitorData.send($scope.myform, newValue, TimeCounter.getTimeElapsed());
}
});
//Fire event when window is scrolled
/*$window.onscroll = function(){
if(!NOSCROLL){
var scrollTop = $(window).scrollTop();
var elemBox = document.getElementsByClassName('activeField')[0].getBoundingClientRect();
var fieldTop = elemBox.top;
var fieldBottom = elemBox.bottom;
var field_id, field_index;
var elemHeight = $('.activeField').height();
var submitSectionHeight = $('.form-actions').height();
var maxScrollTop = $(document).height() - $(window).height();
var fieldWrapperHeight = $('form_fields').height();
var selector = 'form > .field-directive:nth-of-type(' + String($scope.myform.visible_form_fields.length - 1)+ ')'
var fieldDirectiveHeight = $(selector).height()
var scrollPosition = maxScrollTop - submitSectionHeight - fieldDirectiveHeight*1.2;
var fractionToJump = 0.9;
console.log("fieldBottom < elemHeight * fractionToJump: "+fieldBottom + " < " + elemHeight * fractionToJump);
console.log("fieldTop > elemHeight * fractionToJump: "+fieldTop + " > " + elemHeight * fractionToJump);
console.log('fieldTop: '+fieldTop);
console.log('fieldBottom: '+fieldBottom);
console.log('scrollPosition: '+scrollPosition)
//Focus on field above submit form button
if($scope.selected.index === $scope.myform.visible_form_fields.length){
if(scrollTop < scrollPosition){
field_index = $scope.selected.index-1;
$scope.setActiveField(null, field_index, false);
}
}
//Focus on submit form button
else if($scope.selected.index === $scope.myform.visible_form_fields.length-1 && scrollTop > scrollPosition){
field_index = $scope.selected.index+1;
$scope.setActiveField(FORM_ACTION_ID, field_index, false);
}
//If we scrolled bellow the current field, move to next field
else if(fieldBottom < elemHeight * fractionToJump && $scope.selected.index < $scope.myform.visible_form_fields.length-1){
field_index = $scope.selected.index+1;
$scope.setActiveField(null, field_index, false);
}
//If we scrolled above the current field, move to prev field
else if ( $scope.selected.index !== 0 && fieldTop > elemHeight * fractionToJump) {
field_index = $scope.selected.index-1;
$scope.setActiveField(null, field_index, false);
}
}
$scope.$apply();
};*/
$rootScope.nextField = $scope.nextField = function(){
if($scope.selected && $scope.selected.index > -1){
@ -287,7 +218,7 @@ angular.module('view-form').directive('submitFormDirective', ['$http', 'TimeCoun
}
} else {
//If selected is not defined go to the first field
$rootScope.setActiveField(null, 0, true);
$scope.setActiveField(null, 0, true);
}
};
@ -299,7 +230,7 @@ angular.module('view-form').directive('submitFormDirective', ['$http', 'TimeCoun
};
$rootScope.goToInvalid = $scope.goToInvalid = function() {
var field_id = $('.row.field-directive .ng-invalid.focusOn, .row.field-directive .ng-untouched.focusOn:not(.ng-valid)').first().parents('.row.field-directive').first().attr('data-id');
var field_id = $('.ng-invalid, .ng-untouched').first().parents('.row.field-directive').first().attr('id');
$scope.setActiveField(field_id, null, true);
};

View File

@ -16,6 +16,7 @@
<div class="col-xs-12 field-input">
<div class="control-group input-append">
<input class="focusOn"
name="{{field.fieldType}}{{index}}"
ng-style="{'color': design.colors.answerColor, 'border-color': design.colors.answerColor}"
ng-class="{ 'no-border': !!field.fieldValue }"
ui-date="dateOptions"

View File

@ -15,6 +15,7 @@
</div>
<div class="col-xs-12 field-input">
<ui-select ng-model="field.fieldValue"
name="{{field.fieldType}}{{index}}"
class="dropdown"
theme="selectize"
search-enabled="true"

View File

@ -22,6 +22,7 @@
<label class="btn col-md-5 col-xs-12"
ng-class="{activeBtn: field.fieldValue == 'true'}">
<input class="focusOn"
name="{{field.fieldType}}{{index}}"
ng-style="{'color': design.colors.answerColor, 'border-color': design.colors.answerColor}"
type="radio" value="true"
ng-model="field.fieldValue"
@ -36,6 +37,7 @@
<label class="btn col-md-5 col-md-offset-1 col-xs-12"
ng-class="{activeBtn: field.fieldValue == 'false'}">
<input class="focusOn"
name="{{field.fieldType}}{{index}}"
ng-style="{'color': design.colors.answerColor, 'border-color': design.colors.answerColor}"
type="radio" value="false"
ng-model="field.fieldValue"

View File

@ -26,10 +26,11 @@
{{$index+1}}
</div>
<input ng-style="{'color': design.colors.answerColor, 'border-color': design.colors.answerColor}"
name="{{field.fieldType}}{{index}}"
type="radio" class="focusOn"
value="{{option.option_value}}"
ng-model="field.fieldValue"
ng-model-options="{ debounce: 250 }"
ng-value="field.fieldValue"
ng-required="field.required"
ng-change="$root.nextField()"/>

View File

@ -15,14 +15,13 @@
<div class="col-xs-12 field-input">
<input-stars max="{{field.ratingOptions.steps}}"
ng-init="field.fieldValue = 1"
name="{{field.fieldType}}{{index}}"
on-shape-click="true"
on-star-click="nextField()"
on-star-click="$root.nextField()"
icon-full="{{field.ratingOptions.shape}}"
icon-base="fa fa-3x"
icon-empty="{{field.ratingOptions.shape}}"
ng-model="field.fieldValue"
ng-model-options="{ debounce: 250 }"
ng-required="field.required"
on-enter-or-tab-key="nextField()"
on-tab-and-shift-key="prevField()"

View File

@ -18,6 +18,7 @@
{{ 'ADD_NEW_LINE_INSTR' | translate }}
</small>
<textarea class="textarea focusOn" type="text"
name="{{field.fieldType}}{{index}}"
ng-model="field.fieldValue"
ng-model-options="{ debounce: 250 }"
ng-class="{ 'no-border': !!field.fieldValue }"

View File

@ -1,5 +1,4 @@
<div class="textfield field row"
ng-click="setActiveField(field._id, index, true)">
<div class="textfield field row">
<div class="col-xs-12 field-title row-fluid" ng-style="{'color': design.colors.questionColor}">
<h3 class="col-xs-12">
<small class="field-number">

View File

@ -26,6 +26,7 @@
<label class="btn btn-default col-md-2 col-sm-3 col-xs-7"
style="background: rgba(0,0,0,0.1); text-align:left;">
<input type="radio" value="true"
name="{{field.fieldType}}{{index}}"
class="focusOn"
style="opacity: 0; margin-left: 0px;"
ng-model="field.fieldValue"
@ -45,6 +46,7 @@
style="background: rgba(0,0,0,0.1); text-align:left;">
<input type="radio" value="false"
name="{{field.fieldType}}{{index}}"
style="opacity:0; margin-left:0px;"
ng-model="field.fieldValue"
ng-model-options="{ debounce: 250 }"

View File

@ -41,7 +41,7 @@
<div class="row form-field-wrapper">
<form name="forms.myForm" novalidate class="submission-form">
<div ng-repeat="field in myform.form_fields" ng-if="!field.deletePreserved" data-index="{{$index}}" data-id="{{field._id}}" id="{{field._id}}" class="row field-directive" du-scrollspy="{{field._id}}">
<div ng-repeat="field in myform.form_fields" ng-if="!field.deletePreserved" id="{{field._id}}" class="row field-directive" du-scrollspy="{{field._id}}">
<field-directive field="field" design="myform.design" index="$index" forms="forms">
</field-directive>
</div>
@ -56,7 +56,6 @@
</div>
<button ng-if="!forms.myForm.$invalid" class="Button btn col-sm-2 col-xs-8 focusOn" v-busy="loading" v-busy-label="Please wait" v-pressable ng-disabled="loading || forms.myForm.$invalid" ng-click="submitForm()" on-enter-key-disabled="loading || forms.myForm.$invalid" ng-style="{'background-color':myform.design.colors.buttonColor, 'color':myform.design.colors.buttonTextColor}" style="font-size: 1.6em; margin-left: 1em; margin-top: 1em;">
{{ 'SUBMIT' | translate }}
</button>