Skip to content

Commit 4f7c69a

Browse files
committed
Partial support for readOnly
...or "readonly" for v3, or "readonly" as form override. Works on basic properties, but only partial suport for objects. The bootstrap decorator adds "disabled" to the fieldset, but that only works in some browsers. Others, IE for example will style it but happily accept input.
1 parent a60fc50 commit 4f7c69a

File tree

8 files changed

+137
-12
lines changed

8 files changed

+137
-12
lines changed

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

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,30 @@ 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 === 'select') {
1017
return 'directives/decorators/bootstrap/select.html';
1118
}
12-
if (type === 'checkbox') {
19+
if (form.type === 'checkbox') {
1320
return 'directives/decorators/bootstrap/checkbox.html';
1421
}
15-
if (type === 'number') {
22+
if (form.type === 'number') {
1623
return 'directives/decorators/bootstrap/default.html';
1724
}
18-
if (type === 'submit') {
25+
if (form.type === 'submit') {
1926
return 'directives/decorators/bootstrap/submit.html';
2027
}
28+
2129
return 'directives/decorators/bootstrap/default.html';
2230
};
2331

@@ -37,7 +45,7 @@ function($parse, $compile, $http, $templateCache){
3745
//ok let's replace that template!
3846
//We do this manually since we need to bind ng-model properly and also
3947
//for fieldsets to recurse properly.
40-
$http.get(templateUrl(form.type),{ cache: $templateCache }).then(function(res){
48+
$http.get(templateUrl(form),{ cache: $templateCache }).then(function(res){
4149
var template = res.data.replace('$$value$$','model.'+form.key);
4250
$compile(template)(scope,function(clone){
4351
element.replaceWith(clone);

src/directives/decorators/bootstrap/default.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<div class="form-group" ng-class="{'has-error': hasError()}">
22
<label ng-show="form.title">{{form.title}}</label>
3+
34
<input type="{{form.type}}" class="form-control" ng-required="form.required" ng-model="$$value$$" schema-validate="form.schema">
45

56
<span class="help-block" ng-show="form.description && !hasError()">{{form.description}} </span>
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>
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="form.title">{{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: 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="form.title">{{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: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@ function($compile, schemaForm){
1818
replace: false,
1919
restrict: "A",
2020
transclude: true,
21-
link: function(scope,element,attrs,_,transclude) {
21+
require: '?form',
22+
link: function(scope,element,attrs,formCtrl,transclude) {
23+
24+
//expose form controller on scope so that we don't force authors to use name on form
25+
scope.formCtrl = formCtrl;
2226

2327
//We'd like to handle existing markup,
2428
//besides using it in our template we also

src/services/schema-form.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ angular.module('schemaForm').factory('schemaForm',[function(){
4848
if (schema.default) f.default = schema.default;
4949
if (schema.maxLength) f.maxlength = schema.maxLength;
5050
if (schema.minLength) f.minlength = schema.maxLength;
51-
if (schema.readOnly) f.readonly = schema.readOnly;
51+
if (schema.readOnly || schema.readonly) f.readonly = schema.readOnly || schema.readonly;
5252
if (schema.minimum) f.minimum = schema.minimum + (schema.exclusiveMinimum?1:0);
5353
if (schema.maximum) f.maximum = schema.maximum - (schema.exclusiveMaximum?1:0);
5454
f.schema = schema;

test/schema-form-test.js

Lines changed: 98 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,102 @@ describe('Schema form',function(){
205205

206206
});
207207

208+
it('should use disable readonly input fields, v3 style',function(){
209+
210+
inject(function($compile,$rootScope){
211+
var scope = $rootScope.$new();
212+
scope.person = {};
213+
214+
scope.schema = {
215+
"type": "object",
216+
"properties": {
217+
"name": { "type": "string", "readonly": true },
218+
"nick": { "type": "string" }
219+
}
220+
};
221+
222+
scope.form = ["*"];
223+
224+
var tmpl = angular.element('<form sf-schema="schema" sf-form="form" sf-model="person"></form>');
225+
226+
$compile(tmpl)(scope);
227+
$rootScope.$apply();
228+
229+
tmpl.children().length.should.be.equal(2);
230+
tmpl.children().eq(0).is('div.form-group').should.be.true;
231+
tmpl.children().eq(0).find('input').is('input[type="text"]').should.be.true;
232+
tmpl.children().eq(0).find('input').attr('disabled').should.be.equal('disabled');
233+
tmpl.children().eq(1).is('div.form-group').should.be.true;
234+
tmpl.children().eq(1).children('input').length.should.equal(1);
235+
expect(tmpl.children().eq(1).children('input').attr('disabled')).to.be.undefined;
236+
});
237+
});
238+
239+
it('should use disable readonly input fields, v4 style',function(){
240+
241+
inject(function($compile,$rootScope){
242+
var scope = $rootScope.$new();
243+
scope.person = {};
244+
245+
scope.schema = {
246+
"type": "object",
247+
"properties": {
248+
"name": { "type": "string", "readOnly": true },
249+
"nick": { "type": "string" }
250+
}
251+
};
252+
253+
scope.form = ["*"];
254+
255+
var tmpl = angular.element('<form sf-schema="schema" sf-form="form" sf-model="person"></form>');
256+
257+
$compile(tmpl)(scope);
258+
$rootScope.$apply();
259+
260+
tmpl.children().length.should.be.equal(2);
261+
tmpl.children().eq(0).is('div.form-group').should.be.true;
262+
tmpl.children().eq(0).find('input').is('input[type="text"]').should.be.true;
263+
tmpl.children().eq(0).find('input').attr('disabled').should.be.equal('disabled');
264+
tmpl.children().eq(1).is('div.form-group').should.be.true;
265+
tmpl.children().eq(1).children('input').length.should.equal(1);
266+
expect(tmpl.children().eq(1).children('input').attr('disabled')).to.be.undefined;
267+
});
268+
});
269+
270+
it('should use disable readonly input fields, form override',function(){
271+
272+
inject(function($compile,$rootScope){
273+
var scope = $rootScope.$new();
274+
scope.person = {};
275+
276+
scope.schema = {
277+
"type": "object",
278+
"properties": {
279+
"name": { "type": "string" },
280+
"nick": { "type": "string", "readOnly": true }
281+
}
282+
};
283+
284+
scope.form = [
285+
{ key: 'name', readonly: true },
286+
{ key: 'nick', readonly: false },
287+
];
288+
289+
var tmpl = angular.element('<form sf-schema="schema" sf-form="form" sf-model="person"></form>');
290+
291+
$compile(tmpl)(scope);
292+
$rootScope.$apply();
293+
294+
tmpl.children().length.should.be.equal(2);
295+
tmpl.children().eq(0).is('div.form-group').should.be.true;
296+
tmpl.children().eq(0).find('input').is('input[type="text"]').should.be.true;
297+
tmpl.children().eq(0).find('input').attr('disabled').should.be.equal('disabled');
298+
tmpl.children().eq(1).is('div.form-group').should.be.true;
299+
tmpl.children().eq(1).children('input').length.should.equal(1);
300+
expect(tmpl.children().eq(1).children('input').attr('disabled')).to.be.undefined;
301+
});
302+
});
303+
208304

209305
it('should use ng-required on required fields',function(){
210306

@@ -281,13 +377,13 @@ describe('Schema form',function(){
281377
"type": "object",
282378
"properties": {
283379
"name": { "type": "string" },
284-
"nick": { "type": "string" }
380+
"nick": { "type": "string", "required": true }
285381
}
286382
};
287383

288384
scope.form = [
289385
{ key: 'name', required: true },
290-
'nick'
386+
{ key: 'nick', required: false },
291387
];
292388

293389
var tmpl = angular.element('<form sf-schema="schema" sf-form="form" sf-model="person"></form>');

0 commit comments

Comments
 (0)