Skip to content

Commit f119fb1

Browse files
committed
New list format for titleMap
titleMap can (and should) be specified as a list of name value objects, { name: ..., value: ...}, instead of just an objects with value as keys. This new format is used internally but old object format is still accepted in form definitions. This solves a number of problems, you can have titleMaps without enums, order of enum is preserved when no titleMap is defined, types with titleMaps can bind agains schema types that are not string, i.e. radiobuttons for a boolean.
1 parent 442fb38 commit f119fb1

File tree

9 files changed

+174
-52
lines changed

9 files changed

+174
-52
lines changed

examples/bootstrap-example.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ <h3>Schema</h3>
8686
{ name: "Complex Key Support", data: 'data/complex-keys.json' },
8787
{ name: "Array", data: 'data/array.json' },
8888
{ name: "Tab Array", data: 'data/tabarray.json' },
89+
{ name: "TitleMap Examples", data: 'data/titlemaps.json' },
8990
{ name: "Kitchen Sink", data: 'data/sink.json' }
9091
];
9192

examples/data/sink.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -175,10 +175,10 @@
175175
{
176176
"key": "radio",
177177
"type": "radios",
178-
"titleMap": {
179-
"Transistor": "Transistor <br> Not the tube kind.",
180-
"Tube": "Tube <br> The tube kind."
181-
}
178+
"titleMap": [
179+
{ "value": "Transistor", "name": "Transistor <br> Not the tube kind." },
180+
{ "value": "Tube", "name": "Tube <br> The tube kind."}
181+
]
182182
},
183183
{
184184
"key": "radiobuttons",

examples/data/titlemaps.json

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
{
2+
"schema": {
3+
"type": "object",
4+
"properties": {
5+
"select": {
6+
"title": "Select without titleMap",
7+
"type": "string",
8+
"enum": ["a","b","c"]
9+
},
10+
"select2": {
11+
"title": "Select with titleMap (old style)",
12+
"type": "string",
13+
"enum": ["a","b","c"]
14+
},
15+
"noenum": { "type": "string", "title": "No enum, but forms says it's a select" },
16+
"array": {
17+
"title": "Array with enum defaults to 'checkboxes'",
18+
"type": "array",
19+
"items": {
20+
"type": "string",
21+
"enum": ["a","b","c"]
22+
}
23+
},
24+
"array2": {
25+
"title": "Array with titleMap",
26+
"type": "array",
27+
"items": {
28+
"type": "string",
29+
"enum": ["a","b","c"]
30+
}
31+
},
32+
"radios": {
33+
"title": "Basic radio button example",
34+
"type": "string",
35+
"enum": ["a","b","c"]
36+
},
37+
"radiobuttons": {
38+
"title": "Radio buttons used to switch a boolean",
39+
"type": "boolean",
40+
"default": false
41+
}
42+
}
43+
},
44+
"form": [
45+
"select",
46+
{
47+
"key": "select2",
48+
"type": "select",
49+
"titleMap": {
50+
"a": "A",
51+
"b": "B",
52+
"c": "C"
53+
}
54+
},
55+
{
56+
"key": "noenum",
57+
"type": "select",
58+
"titleMap": [
59+
{ "value":"a", "name": "A" },
60+
{ "value":"b", "name":"B" },
61+
{ "value":"c", "name":"C" }
62+
]
63+
},
64+
"array",
65+
{
66+
"key": "array2",
67+
"type": "checkboxes",
68+
"titleMap": [
69+
{ "value":"a", "name": "A" },
70+
{ "value":"b", "name":"B" },
71+
{ "value":"c", "name":"C" }
72+
]
73+
},
74+
{
75+
"key": "radios",
76+
"type": "radios",
77+
"titleMap": [
78+
{ "value":"c", "name": "C" },
79+
{ "value":"b", "name":"B" },
80+
{ "value":"a", "name":"A" }
81+
]
82+
},
83+
{
84+
"key":"radiobuttons",
85+
"type": "radiobuttons",
86+
"titleMap": [
87+
{"value": false, "name": "No way"},
88+
{"value": true, "name": "OK"}
89+
]
90+
}
91+
]
92+
}

src/directives/decorators/bootstrap/checkboxes.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
<div class="form-group" ng-class="{'has-error': hasError(), 'has-success': hasSuccess()}" ng-init="checkboxValues = listToCheckboxValues($$value$$)">
22
<label ng-show="showTitle()">{{form.title}}</label>
3-
<div class="checkbox" ng-repeat="value in form.schema.items.enum" >
3+
<div class="checkbox" ng-repeat="item in form.titleMap" >
44
<label>
55
<input type="checkbox"
66
sf-changed="form"
7-
ng-model="checkboxValues[value]"
7+
ng-model="checkboxValues[item.value]"
88
ng-change="$$value$$ = checkboxValuesToList(checkboxValues)" >
9-
<span ng-bind-html="form.titleMap[value] || value"></span>
9+
<span ng-bind-html="item.name"></span>
1010
</label>
1111

1212
</div>

src/directives/decorators/bootstrap/radio-buttons.html

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
<div class="form-group" ng-class="{'has-error': hasError(), 'has-success': hasSuccess()}">
22
<label ng-show="showTitle()">{{form.title}}</label>
33
<div class="btn-group">
4-
<label class="btn {{ (value === $$value$$) ? form.style.selected || 'btn-primary' : form.style.unselected || 'btn-primary'; }}"
5-
ng-class="{ active: value === $$value$$ }"
6-
ng-repeat="(value,name) in form.titleMap">
4+
<label class="btn {{ (item.value === $$value$$) ? form.style.selected || 'btn-primary' : form.style.unselected || 'btn-primary'; }}"
5+
ng-class="{ active: item.value === $$value$$ }"
6+
ng-repeat="item in form.titleMap">
77
<input type="radio"
88
sf-changed="form"
99
style="display: none;"
1010
ng-model="$$value$$"
11-
ng-value="value">
12-
<span ng-bind-html="name"></span>
11+
ng-value="item.value">
12+
<span ng-bind-html="item.name"></span>
1313
</label>
1414
</div>
1515
<div class="help-block" ng-show="form.description" ng-bind-html="form.description"></div>

src/directives/decorators/bootstrap/radios.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
<div class="form-group" ng-class="{'has-error': hasError(), 'has-success': hasSuccess()}">
22
<label ng-show="showTitle()">{{form.title}}</label>
3-
<div class="radio" ng-repeat="(value,name) in form.titleMap" >
3+
<div class="radio" ng-repeat="item in form.titleMap" >
44
<label>
55
<input type="radio"
66
sf-changed="form"
77
ng-model="$$value$$"
8-
ng-value="value">
9-
<span ng-bind-html="name"></span>
8+
ng-value="item.value">
9+
<span ng-bind-html="item.name"></span>
1010
</label>
1111
</div>
1212
<div class="help-block" ng-show="form.description" ng-bind-html="form.description"></div>

src/directives/decorators/bootstrap/select.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
class="form-control"
88
schema-validate="form.schema"
99
ng-required="form.required"
10-
ng-options="val as form.titleMap[val] for val in form.schema.enum">
10+
ng-options="item.value as item.name for item in form.titleMap">
1111
</select>
1212
<div class="help-block" ng-show="form.description" ng-bind-html="(hasError() && errorMessage(schemaError())) || form.description"></div>
1313
</div>

src/services/schema-form.js

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,28 @@
55
*/
66
angular.module('schemaForm').provider('schemaForm',['sfPathProvider', function(sfPathProvider){
77

8+
//Creates an default titleMap list from an enum, i.e. a list of strings.
9+
var enumToTitleMap = function(enm) {
10+
var titleMap = []; //canonical titleMap format is a list.
11+
enm.forEach(function(name){
12+
titleMap.push({ name: name, value: name});
13+
});
14+
return titleMap;
15+
};
16+
17+
// Takes a titleMap in either object or list format and returns one in
18+
// in the list format.
19+
var canonicalTitleMap = function(titleMap) {
20+
if (!angular.isArray(titleMap)) {
21+
var canonical = [];
22+
angular.forEach(titleMap, function(name,value) {
23+
canonical.push({ name: name, value: value });
24+
});
25+
return canonical;
26+
}
27+
return titleMap;
28+
};
29+
830
var defaultFormDefinition = function(name,schema,options){
931
var rules = defaults[schema.type];
1032
if (rules) {
@@ -34,7 +56,7 @@ angular.module('schemaForm').provider('schemaForm',['sfPathProvider', function(s
3456

3557
//Non standard attributes
3658
if (schema.validationMessage) f.validationMessage = schema.validationMessage;
37-
if (schema.enumNames) f.titleMap = schema.enumNames;
59+
if (schema.enumNames) f.titleMap = canonicalTitleMap(schema.enumNames);
3860
f.schema = schema;
3961
return f;
4062
};
@@ -89,10 +111,7 @@ angular.module('schemaForm').provider('schemaForm',['sfPathProvider', function(s
89111
f.key = options.path;
90112
f.type = 'select';
91113
if (!f.titleMap) {
92-
f.titleMap = {};
93-
schema.enum.forEach(function(name){
94-
f.titleMap[name] = name;
95-
});
114+
f.titleMap = enumToTitleMap(schema.enum);
96115
}
97116
options.lookup[sfPathProvider.stringify(options.path)] = f;
98117
return f;
@@ -105,10 +124,7 @@ angular.module('schemaForm').provider('schemaForm',['sfPathProvider', function(s
105124
f.key = options.path;
106125
f.type = 'checkboxes';
107126
if (!f.titleMap) {
108-
f.titleMap = {};
109-
schema.items.enum.forEach(function(name){
110-
f.titleMap[name] = name;
111-
});
127+
f.titleMap = enumToTitleMap(schema.items.enum);
112128
}
113129
options.lookup[sfPathProvider.stringify(options.path)] = f;
114130
return f;
@@ -254,7 +270,6 @@ angular.module('schemaForm').provider('schemaForm',['sfPathProvider', function(s
254270
form = form || ["*"];
255271

256272
var stdForm = service.defaults(schema,ignore);
257-
258273
//simple case, we have a "*", just put the stdForm there
259274
var idx = form.indexOf("*");
260275
if (idx !== -1) {
@@ -276,6 +291,11 @@ angular.module('schemaForm').provider('schemaForm',['sfPathProvider', function(s
276291
obj = { key: obj };
277292
}
278293

294+
//If it has a titleMap make sure it's a list
295+
if (obj.titleMap) {
296+
obj.titleMap = canonicalTitleMap(obj.titleMap);
297+
}
298+
279299
//if it's a type with items, merge 'em!
280300
if (obj.items) {
281301
obj.items = service.merge(schema,obj.items,ignore);
@@ -293,6 +313,7 @@ angular.module('schemaForm').provider('schemaForm',['sfPathProvider', function(s
293313
if(typeof obj.key == 'string') {
294314
obj.key = sfPathProvider.parse(obj.key);
295315
}
316+
296317
var str = sfPathProvider.stringify(obj.key);
297318
if(lookup[str]){
298319
return angular.extend(lookup[str],obj);

0 commit comments

Comments
 (0)