Skip to content

Commit 9ef8600

Browse files
committed
Merge branch 'hotfix/0.8.8' into development
2 parents 4a89deb + dab0024 commit 9ef8600

File tree

9 files changed

+176
-58
lines changed

9 files changed

+176
-58
lines changed

CHANGELOG

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
1+
v0.8.8
2+
------
3+
* Don't rely on documentFragment.children @davidlgj
4+
* Restored "template" type support with the builder. @davidlgj
5+
* Fixed defaults in array items. @davidlgj
6+
17
v0.8.7
28
------
3-
* Moved common builder functions from angular-schema-form-bootstrap decorator.
4-
* Bugfx for the new builder.
9+
* Moved common builder functions from angular-schema-form-bootstrap decorator. @davidlgj
10+
* Bugfx for the new builder. @davidlgj
511

612
v0.8.6
713
------
8-
* Removed left over console.timeEnd
14+
* Removed left over console.timeEnd @davidlgj
915

1016
v0.8.5
1117
------

dist/schema-form.js

Lines changed: 82 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ angular.module('schemaForm').provider('sfBuilder', ['sfPathProvider', function(s
255255
'"modelValue": model' + (strKey[0] === '[' ? '' : '.') + strKey + '})';
256256
}
257257

258-
var children = args.fieldFrag.children;
258+
var children = args.fieldFrag.children || args.fieldFrag.childNodes;
259259
for (var i = 0; i < children.length; i++) {
260260
var child = children[i];
261261
var ngIf = child.getAttribute('ng-if');
@@ -351,7 +351,7 @@ angular.module('schemaForm').provider('sfBuilder', ['sfPathProvider', function(s
351351
// measure optmization. A good start is probably a cache of DOM nodes for a particular
352352
// template that can be cloned instead of using innerHTML
353353
var div = document.createElement('div');
354-
var template = templateFn(field.template) || templateFn([decorator['default'].template]);
354+
var template = templateFn(f, field) || templateFn(f, decorator['default']);
355355
div.innerHTML = template;
356356

357357
// Move node to a document fragment, we don't want the div.
@@ -375,11 +375,14 @@ angular.module('schemaForm').provider('sfBuilder', ['sfPathProvider', function(s
375375

376376
};
377377

378+
// Let the form definiton override builders if it wants to.
379+
var builderFn = f.builder || field.builder;
380+
378381
// Builders are either a function or a list of functions.
379-
if (typeof field.builder === 'function') {
380-
field.builder(args);
382+
if (typeof builderFn === 'function') {
383+
builderFn(args);
381384
} else {
382-
field.builder.forEach(function(fn) { fn(args); });
385+
builderFn.forEach(function(fn) { fn(args); });
383386
}
384387

385388
// Append
@@ -396,8 +399,11 @@ angular.module('schemaForm').provider('sfBuilder', ['sfPathProvider', function(s
396399
* Builds a form from a canonical form definition
397400
*/
398401
build: function(form, decorator, slots, lookup) {
399-
return build(form, decorator, function(url) {
400-
return $templateCache.get(url);
402+
return build(form, decorator, function(form, field) {
403+
if (form.type === 'template') {
404+
return form.template;
405+
}
406+
return $templateCache.get(field.template);
401407
}, slots, undefined, undefined, lookup);
402408

403409
},
@@ -1332,7 +1338,7 @@ angular.module('schemaForm').provider('schemaForm',
13321338

13331339
var service = {};
13341340

1335-
service.merge = function(schema, form, ignore, options, readonly) {
1341+
service.merge = function(schema, form, ignore, options, readonly, asyncTemplates) {
13361342
form = form || ['*'];
13371343
options = options || {};
13381344

@@ -1403,13 +1409,13 @@ angular.module('schemaForm').provider('schemaForm',
14031409

14041410
//if it's a type with items, merge 'em!
14051411
if (obj.items) {
1406-
obj.items = service.merge(schema, obj.items, ignore, options, obj.readonly);
1412+
obj.items = service.merge(schema, obj.items, ignore, options, obj.readonly, asyncTemplates);
14071413
}
14081414

14091415
//if its has tabs, merge them also!
14101416
if (obj.tabs) {
14111417
angular.forEach(obj.tabs, function(tab) {
1412-
tab.items = service.merge(schema, tab.items, ignore, options, obj.readonly);
1418+
tab.items = service.merge(schema, tab.items, ignore, options, obj.readonly, asyncTemplates);
14131419
});
14141420
}
14151421

@@ -1418,6 +1424,13 @@ angular.module('schemaForm').provider('schemaForm',
14181424
if (obj.type === 'checkbox' && angular.isUndefined(obj.schema['default'])) {
14191425
obj.schema['default'] = false;
14201426
}
1427+
1428+
// Special case: template type with tempplateUrl that's needs to be loaded before rendering
1429+
// TODO: this is not a clean solution. Maybe something cleaner can be made when $ref support
1430+
// is introduced since we need to go async then anyway
1431+
if (asyncTemplates && obj.type === 'template' && !obj.template && obj.templateUrl) {
1432+
asyncTemplates.push(obj);
1433+
}
14211434

14221435
return obj;
14231436
}));
@@ -2289,28 +2302,52 @@ function(sel, sfPath, schemaForm) {
22892302
});
22902303

22912304
scope.appendToArray = function() {
2292-
22932305
var empty;
22942306

2295-
// Same old add empty things to the array hack :(
2296-
if (scope.form && scope.form.schema) {
2297-
if (scope.form.schema.items) {
2298-
if (scope.form.schema.items.type === 'object') {
2299-
empty = {};
2300-
} else if (scope.form.schema.items.type === 'array') {
2301-
empty = [];
2302-
}
2303-
}
2304-
}
2305-
2307+
// Create and set an array if needed.
23062308
var model = scope.modelArray;
23072309
if (!model) {
2308-
// Create and set an array if needed.
23092310
var selection = sfPath.parse(attrs.sfNewArray);
23102311
model = [];
23112312
sel(selection, scope, model);
23122313
scope.modelArray = model;
23132314
}
2315+
2316+
// Same old add empty things to the array hack :(
2317+
if (scope.form && scope.form.schema && scope.form.schema.items) {
2318+
2319+
var items = scope.form.schema.items;
2320+
if (items.type && items.type.indexOf('object') !== -1) {
2321+
empty = {};
2322+
2323+
// Check for possible defaults
2324+
if (!scope.options || scope.options.setSchemaDefaults !== false) {
2325+
empty = angular.isDefined(items['default']) ? items['default'] : empty;
2326+
2327+
// Check for defaults further down in the schema.
2328+
// If the default instance sets the new array item to something falsy, i.e. null
2329+
// then there is no need to go further down.
2330+
if (empty) {
2331+
schemaForm.traverseSchema(items, function(prop, path) {
2332+
if (angular.isDefined(prop['default'])) {
2333+
sel(path, empty, prop['default']);
2334+
}
2335+
});
2336+
}
2337+
}
2338+
2339+
} else if (items.type && items.type.indexOf('array') !== -1) {
2340+
empty = [];
2341+
if (!scope.options || scope.options.setSchemaDefaults !== false) {
2342+
empty = items['default'] || empty;
2343+
}
2344+
} else {
2345+
// No type? could still have defaults.
2346+
if (!scope.options || scope.options.setSchemaDefaults !== false) {
2347+
empty = items['default'] || empty;
2348+
}
2349+
}
2350+
}
23142351
model.push(empty);
23152352

23162353
return model;
@@ -2377,8 +2414,8 @@ FIXME: real documentation
23772414

23782415
angular.module('schemaForm')
23792416
.directive('sfSchema',
2380-
['$compile', 'schemaForm', 'schemaFormDecorators', 'sfSelect', 'sfPath', 'sfBuilder',
2381-
function($compile, schemaForm, schemaFormDecorators, sfSelect, sfPath, sfBuilder) {
2417+
['$compile', '$http', '$templateCache', '$q','schemaForm', 'schemaFormDecorators', 'sfSelect', 'sfPath', 'sfBuilder',
2418+
function($compile, $http, $templateCache, $q, schemaForm, schemaFormDecorators, sfSelect, sfPath, sfBuilder) {
23822419

23832420
return {
23842421
scope: {
@@ -2437,8 +2474,27 @@ angular.module('schemaForm')
24372474

24382475
// Common renderer function, can either be triggered by a watch or by an event.
24392476
var render = function(schema, form) {
2440-
var merged = schemaForm.merge(schema, form, ignore, scope.options);
2477+
var asyncTemplates = [];
2478+
var merged = schemaForm.merge(schema, form, ignore, scope.options, undefined, asyncTemplates);
2479+
2480+
if (asyncTemplates.length > 0) {
2481+
// Pre load all async templates and put them on the form for the builder to use.
2482+
$q.all(asyncTemplates.map(function(form) {
2483+
return $http.get(form.templateUrl, {cache: $templateCache}).then(function(res) {
2484+
form.template = res.data;
2485+
});
2486+
})).then(function() {
2487+
internalRender(schema, form, merged);
2488+
});
2489+
2490+
} else {
2491+
internalRender(schema, form, merged);
2492+
}
2493+
2494+
2495+
};
24412496

2497+
var internalRender = function(schema, form, merged) {
24422498
// Create a new form and destroy the old one.
24432499
// Not doing keeps old form elements hanging around after
24442500
// they have been removed from the DOM

dist/schema-form.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ scope.$broadcast('schemaForm.error.name','usernameAlreadyTaken','The username is
372372
This will invalidate the field and therefore the form and show the error message where it normally
373373
pops up, under the field for instance.
374374
375-
There is a catch though, schema form can't now when this field is valid s you have to tell it by
375+
There is a catch though, schema form can't know when this field is valid so you have to tell it by
376376
sending an event again, this time switch out the validation message for validity of the field,
377377
i.e. `true`.
378378

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "angular-schema-form",
3-
"version": "0.8.7",
3+
"version": "0.8.8",
44
"description": "Create complex forms from a JSON schema with angular.",
55
"repository": "Textalk/angular-schema-form",
66
"main": "dist/schema-form.min.js",

src/directives/newArray.js

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -129,28 +129,52 @@ function(sel, sfPath, schemaForm) {
129129
});
130130

131131
scope.appendToArray = function() {
132-
133132
var empty;
134133

135-
// Same old add empty things to the array hack :(
136-
if (scope.form && scope.form.schema) {
137-
if (scope.form.schema.items) {
138-
if (scope.form.schema.items.type === 'object') {
139-
empty = {};
140-
} else if (scope.form.schema.items.type === 'array') {
141-
empty = [];
142-
}
143-
}
144-
}
145-
134+
// Create and set an array if needed.
146135
var model = scope.modelArray;
147136
if (!model) {
148-
// Create and set an array if needed.
149137
var selection = sfPath.parse(attrs.sfNewArray);
150138
model = [];
151139
sel(selection, scope, model);
152140
scope.modelArray = model;
153141
}
142+
143+
// Same old add empty things to the array hack :(
144+
if (scope.form && scope.form.schema && scope.form.schema.items) {
145+
146+
var items = scope.form.schema.items;
147+
if (items.type && items.type.indexOf('object') !== -1) {
148+
empty = {};
149+
150+
// Check for possible defaults
151+
if (!scope.options || scope.options.setSchemaDefaults !== false) {
152+
empty = angular.isDefined(items['default']) ? items['default'] : empty;
153+
154+
// Check for defaults further down in the schema.
155+
// If the default instance sets the new array item to something falsy, i.e. null
156+
// then there is no need to go further down.
157+
if (empty) {
158+
schemaForm.traverseSchema(items, function(prop, path) {
159+
if (angular.isDefined(prop['default'])) {
160+
sel(path, empty, prop['default']);
161+
}
162+
});
163+
}
164+
}
165+
166+
} else if (items.type && items.type.indexOf('array') !== -1) {
167+
empty = [];
168+
if (!scope.options || scope.options.setSchemaDefaults !== false) {
169+
empty = items['default'] || empty;
170+
}
171+
} else {
172+
// No type? could still have defaults.
173+
if (!scope.options || scope.options.setSchemaDefaults !== false) {
174+
empty = items['default'] || empty;
175+
}
176+
}
177+
}
154178
model.push(empty);
155179

156180
return model;

src/directives/schema-form.js

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ FIXME: real documentation
55

66
angular.module('schemaForm')
77
.directive('sfSchema',
8-
['$compile', 'schemaForm', 'schemaFormDecorators', 'sfSelect', 'sfPath', 'sfBuilder',
9-
function($compile, schemaForm, schemaFormDecorators, sfSelect, sfPath, sfBuilder) {
8+
['$compile', '$http', '$templateCache', '$q','schemaForm', 'schemaFormDecorators', 'sfSelect', 'sfPath', 'sfBuilder',
9+
function($compile, $http, $templateCache, $q, schemaForm, schemaFormDecorators, sfSelect, sfPath, sfBuilder) {
1010

1111
return {
1212
scope: {
@@ -65,8 +65,27 @@ angular.module('schemaForm')
6565

6666
// Common renderer function, can either be triggered by a watch or by an event.
6767
var render = function(schema, form) {
68-
var merged = schemaForm.merge(schema, form, ignore, scope.options);
68+
var asyncTemplates = [];
69+
var merged = schemaForm.merge(schema, form, ignore, scope.options, undefined, asyncTemplates);
70+
71+
if (asyncTemplates.length > 0) {
72+
// Pre load all async templates and put them on the form for the builder to use.
73+
$q.all(asyncTemplates.map(function(form) {
74+
return $http.get(form.templateUrl, {cache: $templateCache}).then(function(res) {
75+
form.template = res.data;
76+
});
77+
})).then(function() {
78+
internalRender(schema, form, merged);
79+
});
80+
81+
} else {
82+
internalRender(schema, form, merged);
83+
}
84+
85+
86+
};
6987

88+
var internalRender = function(schema, form, merged) {
7089
// Create a new form and destroy the old one.
7190
// Not doing keeps old form elements hanging around after
7291
// they have been removed from the DOM

src/services/builder.js

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ angular.module('schemaForm').provider('sfBuilder', ['sfPathProvider', function(s
113113
'"modelValue": model' + (strKey[0] === '[' ? '' : '.') + strKey + '})';
114114
}
115115

116-
var children = args.fieldFrag.children;
116+
var children = args.fieldFrag.children || args.fieldFrag.childNodes;
117117
for (var i = 0; i < children.length; i++) {
118118
var child = children[i];
119119
var ngIf = child.getAttribute('ng-if');
@@ -209,7 +209,7 @@ angular.module('schemaForm').provider('sfBuilder', ['sfPathProvider', function(s
209209
// measure optmization. A good start is probably a cache of DOM nodes for a particular
210210
// template that can be cloned instead of using innerHTML
211211
var div = document.createElement('div');
212-
var template = templateFn(field.template) || templateFn([decorator['default'].template]);
212+
var template = templateFn(f, field) || templateFn(f, decorator['default']);
213213
div.innerHTML = template;
214214

215215
// Move node to a document fragment, we don't want the div.
@@ -233,11 +233,14 @@ angular.module('schemaForm').provider('sfBuilder', ['sfPathProvider', function(s
233233

234234
};
235235

236+
// Let the form definiton override builders if it wants to.
237+
var builderFn = f.builder || field.builder;
238+
236239
// Builders are either a function or a list of functions.
237-
if (typeof field.builder === 'function') {
238-
field.builder(args);
240+
if (typeof builderFn === 'function') {
241+
builderFn(args);
239242
} else {
240-
field.builder.forEach(function(fn) { fn(args); });
243+
builderFn.forEach(function(fn) { fn(args); });
241244
}
242245

243246
// Append
@@ -254,8 +257,11 @@ angular.module('schemaForm').provider('sfBuilder', ['sfPathProvider', function(s
254257
* Builds a form from a canonical form definition
255258
*/
256259
build: function(form, decorator, slots, lookup) {
257-
return build(form, decorator, function(url) {
258-
return $templateCache.get(url);
260+
return build(form, decorator, function(form, field) {
261+
if (form.type === 'template') {
262+
return form.template;
263+
}
264+
return $templateCache.get(field.template);
259265
}, slots, undefined, undefined, lookup);
260266

261267
},

0 commit comments

Comments
 (0)