Skip to content

Commit e08f436

Browse files
committed
Merge branch 'release/oncemoreuntothebreach'
2 parents 4bf91b4 + 9f929fa commit e08f436

19 files changed

+613
-42
lines changed

bower.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.0.1",
3+
"version": "0.0.2",
44
"authors": [
55
"Textalk",
66
"David Jensen <david.lgj@gmail.com>"

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.0.1",
3+
"version": "0.0.2",
44
"description": "Create forms from a JSON schema",
55
"scripts": {
66
"test": "echo \"Error: no test specified\" && exit 1"

problem.txt

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
2+
3+
4+
Olika vägar frammåt:
5+
====================
6+
7+
8+
9+
Problemställningen:
10+
-------------------
11+
json-form fixar en hel del validering, dels genom att läggapå attribut som
12+
min och max på input och dels genom att validera via en schema validtor.
13+
14+
Jag tänkte undvika validatorn och köra "the angular way" genom att ha all validering
15+
i formuläret via HTML5 valideringar och directives som ng-pattern, ng-maxlength osv
16+
antagligen ett par egna.
17+
18+
Hittils har algoritmen sett ut såhär:
19+
#1 schema => defaultForm,
20+
#2 defaultForm+form => finalForm
21+
#3 loopa finalForm och skapa html, dvs all info för validering i formuläret.
22+
23+
Kruxet är att formulär definitionen i json form *inte* innehåller tillräckligt med valideringar
24+
(den innehåller några) utan jag måste lägga till form attribut för dem. (json form tar dem från
25+
schemat)
26+
27+
tex så om schema innehåller "maxLength" attribut så sätts "maxlength" på input fältet, men om form
28+
definitionen innehåller "maxLength" (eller "maxlength" för den delen) så händer inget.
29+
30+
I min algoritm ovan där form definitionen måste innehålla all info för generering av html och
31+
de attribut som styr upp validering så måste jag helt enkelt hitta på eget.
32+
33+
Frågan är hur ska detta egna se ut?
34+
35+
36+
#1 Egna form attribut
37+
När det inte finns ngt form attribut i json forms defintion så skapar jag ett eget, t.ex. så skulle
38+
maxLength bara kopieras till form objektet.
39+
+ minsta motståndets lag
40+
- kluddig lösning, motverkar lite att vara json form kompatibel
41+
- kan allt stödjas?
42+
43+
44+
#2 Eget schema directive
45+
Istället skapa ett eget directive som antingen validerar själv eller lägger till de attribut som
46+
behövs för att validera. Schemat fås genom require och ng-model värdet pekar ut vart i schemat.
47+
Kan möjligtvis implementeras med tv4.
48+
+ snygg lösning
49+
- krångligt directive, måste ta hänsyn till om tex maximum, required osv redan satts via form
50+
definitionen.
51+
52+
53+
54+

src/bootstrap-example.html

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@ <h1>Schema Form Example</h1>
1818
<div class="row">
1919
<div class="col-sm-6">
2020
<h3>The Generated Form</h3>
21-
<form sf-model="person" sf-form="form" sf-schema="schema" sf-decorator="{{decorator}}">
22-
21+
<form name="ngform" sf-model="person" sf-form="form" sf-schema="schema" sf-decorator="{{decorator}}">
2322
</form>
2423
</div>
2524
<div class="col-sm-6">
@@ -51,11 +50,13 @@ <h3>Model</h3>
5150

5251
$scope.schema = {
5352
"type": "object",
53+
"required": ['name','shoesize'],
5454
"properties": {
5555
"name": {
5656
"title": "Name",
5757
"description": "Gimme yea name lad",
5858
"type": "string",
59+
"pattern": "^[^/]*$",
5960
"minLength": 2
6061
},
6162
"favorite": {
@@ -69,7 +70,8 @@ <h3>Model</h3>
6970
},
7071
"shoesize": {
7172
"title": "Shoe size",
72-
"type": "number"
73+
"default": 42,
74+
"type": "number",
7375
},
7476
"attributes": {
7577
"type": "object",
@@ -88,6 +90,16 @@ <h3>Model</h3>
8890
}
8991
}
9092
},
93+
"things": {
94+
"type": "array",
95+
"title": "I like...",
96+
"items": {
97+
"type": "string",
98+
"enum": [
99+
"clowns","compiling","sleeping"
100+
]
101+
}
102+
},
91103
"soul": {
92104
"title": "Terms Of Service",
93105
"description": "I agree to sell my undying soul",
@@ -99,7 +111,13 @@ <h3>Model</h3>
99111

100112
$scope.form = [
101113
'*',
102-
{ type: 'submit', title: 'Do It!'}
114+
{
115+
type: 'actions',
116+
items: [
117+
{ type: 'submit', title: 'Do It!'},
118+
{ type: 'button', title: 'Noooooooooooo'}
119+
]
120+
}
103121
];
104122

105123
$scope.decorator = 'bootstrap-decorator';
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<div class="btn-group">
2+
<input ng-repeat-start="item in form.items"
3+
type="submit"
4+
class="btn btn-primary"
5+
value="item.title"
6+
ng-if="item.type === 'submit'">
7+
<button ng-repeat-end class="btn btn-default" ng-if="item.type !== 'submit'">{{item.title}}</button>
8+
</div>

src/directives/decorators/bootstrap/bootstrap-decorator.js

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,39 @@ angular.module('schemaForm').directive('bootstrapDecorator',
22
['$parse','$compile','$http','$templateCache',
33
function($parse, $compile, $http, $templateCache){
44

5-
var templateUrl = function(type) {
6-
if (type === 'fieldset') {
5+
var templateUrl = function(form) {
6+
//readonly is a special case
7+
if (form.readonly && form.key && form.type !== 'fieldset') {
8+
return 'directives/decorators/bootstrap/readonly.html';
9+
}
10+
if (form.type === 'textarea') {
11+
return 'directives/decorators/bootstrap/textarea.html';
12+
}
13+
if (form.type === 'fieldset') {
714
return 'directives/decorators/bootstrap/fieldset.html';
815
}
9-
if (type === 'select') {
16+
if (form.type === 'section') {
17+
return 'directives/decorators/bootstrap/section.html';
18+
}
19+
if (form.type === 'actions') {
20+
return 'directives/decorators/bootstrap/actions.html';
21+
}
22+
if (form.type === 'select') {
1023
return 'directives/decorators/bootstrap/select.html';
1124
}
12-
if (type === 'checkbox') {
25+
if (form.type === 'checkbox') {
1326
return 'directives/decorators/bootstrap/checkbox.html';
1427
}
15-
if (type === 'number') {
16-
return 'directives/decorators/bootstrap/number.html';
28+
if (form.type === 'checkboxes') {
29+
return 'directives/decorators/bootstrap/checkboxes.html';
30+
}
31+
if (form.type === 'number') {
32+
return 'directives/decorators/bootstrap/default.html';
1733
}
18-
if (type === 'submit') {
34+
if (form.type === 'submit') {
1935
return 'directives/decorators/bootstrap/submit.html';
2036
}
37+
2138
return 'directives/decorators/bootstrap/default.html';
2239
};
2340

@@ -28,7 +45,6 @@ function($parse, $compile, $http, $templateCache){
2845
replace: true,
2946
transclude: false,
3047
scope: true,
31-
3248
link: function(scope,element,attrs) {
3349

3450
//rebind our part of the form to the scope.
@@ -38,16 +54,30 @@ function($parse, $compile, $http, $templateCache){
3854
//ok let's replace that template!
3955
//We do this manually since we need to bind ng-model properly and also
4056
//for fieldsets to recurse properly.
41-
$http.get(templateUrl(form.type),{ cache: $templateCache }).then(function(res){
42-
var template = res.data.replace('$$value$$','model.'+form.key);
57+
$http.get(templateUrl(form),{ cache: $templateCache }).then(function(res){
58+
var template = res.data.replace(/\$\$value\$\$/g,'model.'+form.key);
4359
$compile(template)(scope,function(clone){
4460
element.replaceWith(clone);
4561
});
4662
});
4763
once();
4864
});
49-
}
5065

66+
//Keep error prone logic from the template
67+
scope.showTitle = function() {
68+
return scope.form && scope.form.notitle !== true && scope.form.title;
69+
};
70+
71+
scope.checkboxValuesToList = function(values){
72+
var lst = [];
73+
angular.forEach(values,function(v,k){
74+
if (v) {
75+
lst.push(k);
76+
}
77+
});
78+
return lst;
79+
};
80+
}
5181
};
5282
}]);
5383

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
<div class="checkbox">
2-
<label ng-show="form.title">
3-
<input type="checkbox" ng-model="$$value$$" schema-validate="form.schema">
1+
<div class="checkbox" ng-class="{'has-error': hasError()}">
2+
<label>
3+
<input type="checkbox" ng-model="$$value$$" schema-validate="form.schema" ng-required="form.required">
44
{{form.title}}
55
</label>
66

7-
<span class="help-block" ng-show="form.description" >{{form.description}}</span>
7+
<span class="help-block" ng-show="form.description">{{form.description}}</span>
88
</div>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<div class="form-group" ng-class="{'has-error': hasError()}" ng-init="checkboxValues = {}">
2+
<label ng-show="showTitle()">{{form.title}}</label>
3+
<div class="checkbox" ng-repeat="(value,name) in form.titleMap" >
4+
<label>
5+
<input type="checkbox" ng-model="checkboxValues[value]" ng-change="$$value$$ = checkboxValuesToList(checkboxValues)" >
6+
{{name}}
7+
</label>
8+
</div>
9+
<span class="help-block" ng-show="form.description">{{form.description}}</span>
10+
</div>
Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
1-
<div class="form-group" ng-class="{'has-error':ngModel.$invalid}">
2-
<label ng-show="form.title">{{form.title}}</label>
3-
<input type="text" class="form-control" name="" ng-model="$$value$$" schema-validate="form.schema">
4-
<span class="help-block" ng-show="form.description && !ngModel.$invalid">{{form.description}} </span>
5-
<span class="help-block" ng-show="ngModel.$invalid">{{schemaError}}</span>
1+
<div class="form-group" ng-class="{'has-error': hasError()}">
2+
<label ng-show="showTitle()">{{form.title}}</label>
3+
4+
<input type="{{form.type}}"
5+
placeholder="{{form.placeholder}}"
6+
class="form-control"
7+
ng-required="form.required"
8+
ng-model="$$value$$"
9+
schema-validate="form.schema">
10+
11+
<span class="help-block" ng-show="form.description && !hasError()">{{form.description}} </span>
12+
<span class="help-block" ng-show="hasError()">{{schemaError}}</span>
613
</div>
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<fieldset>
1+
<fieldset ng-disabled="form.readonly">
22
<legend ng-show="form.title">{{ form.title }}</legend>
33
<bootstrap-decorator ng-repeat="item in form.items" form="item"></bootstrap-decorator>
44
</fieldset>

src/directives/decorators/bootstrap/number.html

Lines changed: 0 additions & 6 deletions
This file was deleted.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<div class="form-group">
2+
<label ng-show="showTitle()">{{form.title}}</label>
3+
<input ng-if="form.type !== 'textarea'" type="text" disabled class="form-control" value="{{$$value$$}}">
4+
<textarea ng-if="form.type === 'textarea'" disabled class="form-control">{{$$value$$}}</textarea>
5+
<span class="help-block" ng-show="form.description">{{form.description}} </span>
6+
</div>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<div>
2+
<bootstrap-decorator ng-repeat="item in form.items" form="item"></bootstrap-decorator>
3+
</div>
Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1-
<div class="form-group">
2-
<label ng-show="form.title">
1+
<div class="form-group" ng-class="{'has-error': hasError()}">
2+
<label ng-show="showTitle()">
33
{{form.title}}
44
</label>
5-
<select ng-model="$$value$$" class="form-control" schema-validate="form.schema">
6-
<option ng-repeat="(val,name) in form.titleMap" value="{{val}}">{{name}}</option>
5+
<select ng-model="$$value$$"
6+
class="form-control"
7+
schema-validate="form.schema"
8+
ng-required="form.required"
9+
ng-options="val as name for (val,name) in form.titleMap">
710
</select>
8-
<span class="help-block" ng-show="form.description && !ngModel.$invalid">{{form.description}}</span>
9-
<span class="help-block" ng-show="ngModel.$invalid">{{schemaError}}</span>
11+
<span class="help-block" ng-show="form.description && !hasError()">{{form.description}}</span>
12+
<span class="help-block" ng-show="hasError()">{{schemaError}}</span>
1013
</div>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<div class="form-group" ng-class="{'has-error': hasError()}">
2+
<label ng-show="showTitle()">{{form.title}}</label>
3+
<textarea class="form-control"
4+
ng-required="form.required"
5+
ng-model="$$value$$"
6+
schema-validate="form.schema"></textarea>
7+
8+
<span class="help-block" ng-show="form.description && !hasError()">{{form.description}} </span>
9+
<span class="help-block" ng-show="hasError()">{{schemaError}} {{ngModel.$error}}</span>
10+
</div>

src/directives/schema-form.js

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,17 @@ angular.module('schemaForm')
88
['$compile','schemaForm',
99
function($compile, schemaForm){
1010

11+
//recurse through the entire schema.
12+
//FIXME: no support for arrays
13+
var traverse = function(schema,fn,path) {
14+
path = path || "";
15+
fn(schema,path);
16+
angular.forEach(schema.properties,function(prop,name){
17+
traverse(prop,fn,path===""?name:path+'.'+name);
18+
});
19+
};
20+
21+
1122

1223
return {
1324
scope: {
@@ -18,7 +29,11 @@ function($compile, schemaForm){
1829
replace: false,
1930
restrict: "A",
2031
transclude: true,
21-
link: function(scope,element,attrs,_,transclude) {
32+
require: '?form',
33+
link: function(scope,element,attrs,formCtrl,transclude) {
34+
35+
//expose form controller on scope so that we don't force authors to use name on form
36+
scope.formCtrl = formCtrl;
2237

2338
//We'd like to handle existing markup,
2439
//besides using it in our template we also
@@ -41,6 +56,7 @@ function($compile, schemaForm){
4156
var lastDigest = {};
4257

4358
scope.$watch(function(){
59+
4460
var schema = scope.schema;
4561
var form = scope.initialForm || ['*'];
4662

@@ -75,7 +91,18 @@ function($compile, schemaForm){
7591
element[0].appendChild(frag);
7692

7793
//compile only children
94+
7895
$compile(element.children())(scope);
96+
97+
98+
//ok, now that that is done let's set any defaults
99+
traverse(schema,function(prop,path){
100+
//This is probably not so fast, but a simple solution.
101+
if (angular.isDefined(prop['default'])) {
102+
scope.$eval('model.'+path+' = model.'+path+' || defaltValue',{ defaltValue: prop['default']});
103+
}
104+
});
105+
79106
}
80107
});
81108
}

0 commit comments

Comments
 (0)