Skip to content

Commit d5c15e5

Browse files
committed
Merge branch 'master' into messing-2
# Conflicts: # src/client/js/services/record-handler.ts # src/client/less/forms-angular-bs-common.less # src/client/template/base-edit.html
2 parents d81ab6e + 79893aa commit d5c15e5

18 files changed

+328
-233
lines changed

package.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"author": "Mark Chapman <support@forms-angular.org>",
44
"description": "A form builder that sits on top of Angular.js, Twitter Bootstrap, jQuery UI, Angular-UI, Express and Mongoose. Opinionated or what?",
55
"homepage": "http://forms-angular.org",
6-
"version": "0.12.0-beta.46",
6+
"version": "0.12.0-beta.52",
77
"engines": {
88
"node": ">=8.x",
99
"npm": ">=5.x"
@@ -50,8 +50,6 @@
5050
"angular-ui-bootstrap": "1.3.2 || 2.5.6",
5151
"angular-ui-grid": "^4.8.1",
5252
"async": "3.1.0",
53-
"fng-reports": "^0.12.0-beta.46",
54-
"fng-ui-select": "^0.12.0-beta.46",
5553
"lodash": "^4.17.15",
5654
"ng-infinite-scroll": "1.3.0",
5755
"node.extend": "2.0.2"

src/client/index.d.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,8 @@ declare module fng {
169169
export interface IFormInstruction extends IFieldViewInfo {
170170
id? : string; // id of generated DOM element
171171
type?: 'string' | 'text' | 'textarea' | 'number' | 'select' | 'link' | 'date' | 'checkbox' | 'password';
172-
rows? : number
172+
defaultValue? : any;
173+
rows? : number;
173174
label: string;
174175
options?: any;
175176
ids?: any;
@@ -320,6 +321,7 @@ declare module fng {
320321
cancel: () => any;
321322
showError: (error: any, alertTitle? : string) => void;
322323
prepareForSave: (cb: (error: string, dataToSave?: any) => void) => void;
324+
setDefaults: (formSchema: IFormSchema, base?: string) => any;
323325
formSchema: IControlledFormSchema;
324326
baseSchema: () => Array<any>;
325327
setFormDirty: any;

src/client/js/services/form-generator.ts

Lines changed: 48 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,8 @@ module fng.services {
1010
*/
1111

1212
/*@ngInject*/
13-
import IFormController = angular.IFormController;
1413
import IFormInstruction = fng.IFormInstruction;
1514

16-
1715
export function formGenerator($location, $timeout, $filter, SubmissionsService, routingService, recordHandler) : IFormGenerator {
1816

1917
function handleSchema(description, source, destForm, destList, prefix, doRecursion, $scope, ctrlState) {
@@ -44,46 +42,48 @@ module fng.services {
4442
}
4543

4644
for (var field in source) {
47-
if (field === '_id') {
48-
if (destList && source['_id'].options && source['_id'].options.list) {
49-
handleListInfo(destList, source['_id'].options.list, field);
50-
}
51-
} else if (source.hasOwnProperty(field)) {
52-
var mongooseType = source[field],
53-
mongooseOptions: any = mongooseType.options || {};
54-
var formData: any = mongooseOptions.form || {};
55-
if (mongooseType.schema && !formData.hidden) {
56-
if (doRecursion && destForm) {
57-
var schemaSchema = [];
58-
handleSchema('Nested ' + field, mongooseType.schema, schemaSchema, null, field + '.', true, $scope, ctrlState);
59-
var sectionInstructions = basicInstructions(field, formData, prefix);
60-
sectionInstructions.schema = schemaSchema;
61-
if (formData.tab) {
62-
handletabInfo(formData.tab, sectionInstructions);
63-
}
64-
if (formData.order !== undefined) {
65-
destForm.splice(formData.order, 0, sectionInstructions);
66-
} else {
67-
destForm.push(sectionInstructions);
68-
}
45+
if (source.hasOwnProperty(field)) {
46+
if (field === '_id') {
47+
if (destList && source['_id'].options && source['_id'].options.list) {
48+
handleListInfo(destList, source['_id'].options.list, field);
6949
}
70-
} else {
71-
if (destForm && !formData.hidden) {
72-
var formInstructions = basicInstructions(field, formData, prefix);
73-
if (handleConditionals(formInstructions.showIf, formInstructions.name, $scope) && field !== 'options') {
74-
var formInst = handleFieldType(formInstructions, mongooseType, mongooseOptions, $scope, ctrlState);
75-
if (formInst.tab) {
76-
handletabInfo(formInst.tab, formInst);
50+
} else if (source.hasOwnProperty(field)) {
51+
var mongooseType = source[field],
52+
mongooseOptions: any = mongooseType.options || {};
53+
var formData: any = mongooseOptions.form || {};
54+
if (mongooseType.schema && !formData.hidden) {
55+
if (doRecursion && destForm) {
56+
var schemaSchema = [];
57+
handleSchema('Nested ' + field, mongooseType.schema, schemaSchema, null, field + '.', true, $scope, ctrlState);
58+
var sectionInstructions = basicInstructions(field, formData, prefix);
59+
sectionInstructions.schema = schemaSchema;
60+
if (formData.tab) {
61+
handletabInfo(formData.tab, sectionInstructions);
7762
}
7863
if (formData.order !== undefined) {
79-
destForm.splice(formData.order, 0, formInst);
64+
destForm.splice(formData.order, 0, sectionInstructions);
8065
} else {
81-
destForm.push(formInst);
66+
destForm.push(sectionInstructions);
8267
}
8368
}
84-
}
85-
if (destList && mongooseOptions.list) {
86-
handleListInfo(destList, mongooseOptions.list, field);
69+
} else {
70+
if (destForm && !formData.hidden) {
71+
var formInstructions = basicInstructions(field, formData, prefix);
72+
if (handleConditionals(formInstructions.showIf, formInstructions.name, $scope) && field !== 'options') {
73+
var formInst = handleFieldType(formInstructions, mongooseType, mongooseOptions, $scope, ctrlState);
74+
if (formInst.tab) {
75+
handletabInfo(formInst.tab, formInst);
76+
}
77+
if (formData.order !== undefined) {
78+
destForm.splice(formData.order, 0, formInst);
79+
} else {
80+
destForm.push(formInst);
81+
}
82+
}
83+
}
84+
if (destList && mongooseOptions.list) {
85+
handleListInfo(destList, mongooseOptions.list, field);
86+
}
8787
}
8888
}
8989
}
@@ -189,7 +189,8 @@ module fng.services {
189189
} else {
190190
try {
191191
formInstructions.add = formInstructions.add || '';
192-
let testDatePickerInstalled = angular.module('ui.date').requires;
192+
// Check whether DatePicker is installed
193+
angular.module('ui.date').requires;
193194
formInstructions.type = 'text';
194195
formInstructions.add += ' ui-date ui-date-format ';
195196
// formInstructions.add += ' ui-date ui-date-format datepicker-popup-fix ';
@@ -221,6 +222,11 @@ module fng.services {
221222
if (mongooseOptions.readonly) {
222223
formInstructions['readonly'] = true;
223224
}
225+
if (mongooseType.defaultValue !== undefined) {
226+
formInstructions.defaultValue = mongooseType.defaultValue;
227+
} else if (mongooseType.options && mongooseType.options.default !== undefined) {
228+
console.log('No support for default with no value, yet')
229+
}
224230
return formInstructions;
225231
}
226232

@@ -446,7 +452,11 @@ module fng.services {
446452
// check that target element is visible. May not be reliable - see https://stackoverflow.com/questions/19669786/check-if-element-is-visible-in-dom
447453
if ($event.target.offsetParent) {
448454
var arrayField = getArrayFieldToExtend(fieldName, $scope);
449-
arrayField.push({});
455+
456+
const schemaElement = $scope.formSchema.find(f => f.name === fieldName); // In case someone is using the formSchema directly
457+
const subSchema = schemaElement ? schemaElement.schema : null;
458+
let obj = subSchema ? $scope.setDefaults(subSchema, fieldName + '.') : {};
459+
arrayField.push(obj);
450460
$scope.setFormDirty($event);
451461
}
452462
},

src/client/js/services/record-handler.ts

Lines changed: 56 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -499,11 +499,11 @@ module fng.services {
499499
} else {
500500
// New record
501501
ctrlState.allowLocationChange = false;
502-
ctrlState.master = {};
502+
ctrlState.master = $scope.setDefaults($scope.formSchema);
503503
let passedRecord = $scope.initialiseNewRecord || $location.$$search.r;
504504
if (passedRecord) {
505505
try {
506-
ctrlState.master = JSON.parse(passedRecord);
506+
Object.assign(ctrlState.master, JSON.parse(passedRecord));
507507

508508
// Although this is a new record we are making it dirty from the url so we need to $setDirty
509509
$scope.$on("fngCancel", () => {
@@ -845,22 +845,24 @@ module fng.services {
845845
updateObject(fieldname, anObject, function(value) {
846846
return convertToForeignKeys(schemaI, value, $scope[suffixCleanId(schemaI, "Options")], idList);
847847
});
848-
} else if (thisConversion = getConversionObject($scope, fieldname, schemaName)) {
849-
const lookup = getData(anObject, fieldname, null);
850-
let newVal;
851-
if (schemaI.array) {
852-
newVal = [];
853-
if (lookup) {
854-
for (let n = 0; n < lookup.length; n++) {
855-
newVal[n] = convertLookup(lookup[n], thisConversion);
848+
} else {
849+
let thisConversion = getConversionObject($scope, fieldname, schemaName);
850+
if (thisConversion) {
851+
const lookup = getData(anObject, fieldname, null);
852+
let newVal;
853+
if (schemaI.array) {
854+
newVal = [];
855+
if (lookup) {
856+
for (let n = 0; n < lookup.length; n++) {
857+
newVal[n] = convertLookup(lookup[n], thisConversion);
858+
}
856859
}
860+
} else {
861+
newVal = convertLookup(lookup, thisConversion);
857862
}
858-
} else {
859-
newVal = convertLookup(lookup, thisConversion);
863+
setData(anObject, fieldname, null, newVal);
860864
}
861-
setData(anObject, fieldname, null, newVal);
862865
}
863-
864866
}
865867
}
866868
return anObject;
@@ -908,7 +910,7 @@ module fng.services {
908910
$scope.errorHideTimer = window.setTimeout(function() {
909911
$scope.dismissError();
910912
$scope.$digest();
911-
}, 1000 + (1000 * ($scope.alertTitle + $scope.errorMessage).length / 50));
913+
}, 2000 + (1000 * ($scope.alertTitle + $scope.errorMessage).length / 50));
912914
$scope.errorVisible = true;
913915
};
914916

@@ -1092,13 +1094,17 @@ module fng.services {
10921094
$scope.whyDisabled = undefined;
10931095
let pristine = false;
10941096

1095-
if ($scope[$scope.topLevelFormName]) {
1096-
if ($scope[$scope.topLevelFormName].$invalid) {
1097-
$scope.whyDisabled = "The form data is invalid:";
1098-
$scope[$scope.topLevelFormName].$$controls.forEach(c => {
1099-
if (c.$invalid) {
1097+
function generateWhyDisabledMessage(form, subFormName?: string) {
1098+
form.$$controls.forEach(c => {
1099+
if (c.$invalid) {
1100+
if (c.$$controls) {
1101+
// nested form
1102+
generateWhyDisabledMessage(c, c.$name)
1103+
} else {
11001104
$scope.whyDisabled += "<br /><strong>";
1101-
1105+
if (subFormName) {
1106+
$scope.whyDisabled += subFormName + ' ';
1107+
}
11021108
if (
11031109
cssFrameworkService.framework() === "bs2" &&
11041110
c.$$element &&
@@ -1124,20 +1130,29 @@ module fng.services {
11241130
$scope.whyDisabled += "</strong>: ";
11251131
if (c.$error) {
11261132
for (let type in c.$error) {
1127-
switch (type) {
1128-
case "required":
1129-
$scope.whyDisabled += "Field missing required value. ";
1130-
break;
1131-
case "pattern":
1132-
$scope.whyDisabled += "Field does not match required pattern. ";
1133-
break;
1134-
default:
1135-
$scope.whyDisabled += type + ". ";
1133+
if (c.$error.hasOwnProperty(type)) {
1134+
switch (type) {
1135+
case "required":
1136+
$scope.whyDisabled += "Field missing required value. ";
1137+
break;
1138+
case "pattern":
1139+
$scope.whyDisabled += "Field does not match required pattern. ";
1140+
break;
1141+
default:
1142+
$scope.whyDisabled += type + ". ";
1143+
}
11361144
}
11371145
}
11381146
}
11391147
}
1140-
});
1148+
}
1149+
});
1150+
}
1151+
1152+
if ($scope[$scope.topLevelFormName]) {
1153+
if ($scope[$scope.topLevelFormName].$invalid) {
1154+
$scope.whyDisabled = 'The form data is invalid:';
1155+
generateWhyDisabledMessage($scope[$scope.topLevelFormName]);
11411156
} else if ($scope[$scope.topLevelFormName].$pristine) {
11421157
// Don't have disabled message - should be obvious from Cancel being disabled,
11431158
// and the message comes up when the Save button is clicked.
@@ -1180,6 +1195,16 @@ module fng.services {
11801195
}
11811196
};
11821197

1198+
$scope.setDefaults = function(formSchema: IFormInstruction[], base = ''): any {
1199+
const retVal = {};
1200+
formSchema.forEach(s => {
1201+
if (s.defaultValue !== undefined) {
1202+
retVal[s.name.replace(base, '')] = s.defaultValue;
1203+
}
1204+
});
1205+
return retVal;
1206+
};
1207+
11831208
$scope.getVal = function(expression, index) {
11841209
if (expression.indexOf("$index") === -1 || typeof index !== "undefined") {
11851210
expression = expression.replace(/\$index/g, index);

src/client/less/forms-angular-bs-common.less

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ button#saveButton[disabled]:hover + #why-disabled.showwhy {
221221
#display-error.ng-hide {
222222
opacity: 0;
223223
}
224-
#display-error.ng-hide-add,
224+
#display-error.ng-hide-add, // animate the error display
225225
#display-error.ng-hide-remove {
226226
transition: all linear 0.5s;
227227
}
Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
<div id="display-error" ng-style="{opacity : errorMessage ? '1' : '0', 'z-index' : errorMessage ? '130' : '0'}" class="row-fluid">
2-
<div class="alert alert-error offset1 span10 alert-warning ">
3-
<button type="button" class="close" ng-click="dismissError()"><i class="icon-remove"></i></button>
4-
<button type="button" class="close" ng-click="stickError()"><i class="icon-stop"></i></button>
5-
<h4>{{alertTitle}}</h4>
6-
<div ng-bind-html="errorMessage"></div>
7-
</div>
1+
<div id="display-error" ng-show="errorVisible" class="row-fluid ng-hide">
2+
<div class="alert alert-error offset1 span10">
3+
<button type="button" id="err-hide" class="close" ng-click="dismissError()"><i class="icon-remove"></i></button>
4+
<button type="button" id="err-pin" class="close" ng-click="stickError()"><i class="icon-stop"></i></button>
5+
<h4 id="err-title">{{alertTitle}}</h4>
6+
<div id="err-msg" ng-bind-html="errorMessage"></div>
7+
</div>
88
</div>
Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
<div id="display-error" ng-style="{opacity : errorMessage ? '1' : '0', 'z-index' : errorMessage ? '130' : '0'}" class="row">
2-
<div class="alert col-md-offset-1 col-md-10 alert-warning ">
3-
<button type="button" class="close" ng-click="dismissError()"><i class="glyphicon glyphicon-remove"></i></button>
4-
<button type="button" class="close" ng-click="stickError()"><i class="glyphicon glyphicon-pushpin"></i></button>
5-
<h4>{{alertTitle}}</h4>
6-
<div ng-bind-html="errorMessage"></div>
7-
</div>
1+
<div id="display-error" ng-show="errorVisible" class="row ng-hide">
2+
<div class="alert alert-error col-md-offset-1 col-md-10 alert-danger">
3+
<button type="button" id="err-hide" class="close" ng-click="dismissError()"><i class="glyphicon glyphicon-remove"></i></button>
4+
<button type="button" id="err-pin" class="close" ng-click="stickError()"><i class="glyphicon glyphicon-pushpin"></i></button>
5+
<h4 id="err-title">{{alertTitle}}</h4>
6+
<div id="err-msg" ng-bind-html="errorMessage"></div>
7+
</div>
88
</div>

0 commit comments

Comments
 (0)