Skip to content

Commit 20e943c

Browse files
committed
Merge branch 'hotfix/0.8.9' into development
2 parents 7ebab55 + ac199fd commit 20e943c

File tree

12 files changed

+537
-156
lines changed

12 files changed

+537
-156
lines changed

CHANGELOG

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
v0.8.9
2+
------
3+
* Bugfix for radios and radios-inline. Validation should now work.
4+
* Bugfix so model changes from outside the form trigger validation.
5+
* New global option `pristine`. Sets if errors and success states
6+
should be visible when form field are `$pristine`. Default is `{errors: true, success: true}`
7+
18
v0.8.8
29
------
310
* Don't rely on documentFragment.children @davidlgj

dist/schema-form.js

Lines changed: 158 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,13 @@ angular.module('schemaForm').provider('sfBuilder', ['sfPathProvider', function(s
299299
}
300300
};
301301
this.builders = builders;
302+
var stdBuilders = [
303+
builders.sfField,
304+
builders.ngModel,
305+
builders.ngModelOptions,
306+
builders.condition
307+
];
308+
this.stdBuilders = stdBuilders;
302309

303310
this.$get = ['$templateCache', 'schemaFormDecorators', 'sfPath', function($templateCache, schemaFormDecorators, sfPath) {
304311

@@ -326,7 +333,7 @@ angular.module('schemaForm').provider('sfBuilder', ['sfPathProvider', function(s
326333

327334
// Sanity check.
328335
if (!f.type) {
329-
return;
336+
return frag;
330337
}
331338

332339
var field = decorator[f.type] || decorator['default'];
@@ -408,6 +415,7 @@ angular.module('schemaForm').provider('sfBuilder', ['sfPathProvider', function(s
408415

409416
},
410417
builder: builders,
418+
stdBuilders: stdBuilders,
411419
internalBuild: build
412420
};
413421
}];
@@ -812,17 +820,22 @@ angular.module('schemaForm').provider('schemaFormDecorators',
812820

813821

814822
/**
815-
* Create a decorator directive and its sibling "manual" use decorators.
816-
* The directive can be used to create form fields or other form entities.
817-
* It can be used in conjunction with <schema-form> directive in which case the decorator is
818-
* given it's configuration via a the "form" attribute.
823+
* Define a decorator. A decorator is a set of form types with templates and builder functions
824+
* that help set up the form.
819825
*
820-
* ex. Basic usage
821-
* <sf-decorator form="myform"></sf-decorator>
822-
**
823826
* @param {string} name directive name (CamelCased)
824827
* @param {Object} fields, an object that maps "type" => `{ template, builder, replace}`.
825828
attributes `builder` and `replace` are optional, and replace defaults to true.
829+
830+
`template` should be the key of the template to load and it should be pre-loaded
831+
in `$templateCache`.
832+
833+
`builder` can be a function or an array of functions. They will be called in
834+
the order they are supplied.
835+
836+
`replace` (DEPRECATED) is for backwards compatability. If false the builder
837+
will use the "old" way of building that form field using a <sf-decorator>
838+
directive.
826839
*/
827840
this.defineDecorator = function(name, fields) {
828841
decorators[name] = {'__name': name}; // TODO: this feels like a hack, come up with a better way.
@@ -840,6 +853,7 @@ angular.module('schemaForm').provider('schemaFormDecorators',
840853
};
841854

842855
/**
856+
* DEPRECATED
843857
* Creates a directive of a decorator
844858
* Usable when you want to use the decorators without using <schema-form> directive.
845859
* Specifically when you need to reuse styling.
@@ -854,6 +868,7 @@ angular.module('schemaForm').provider('schemaFormDecorators',
854868
this.createDirective = createManualDirective;
855869

856870
/**
871+
* DEPRECATED
857872
* Same as createDirective, but takes an object where key is 'type' and value is 'templateUrl'
858873
* Useful for batching.
859874
* @param {Object} templates
@@ -876,6 +891,7 @@ angular.module('schemaForm').provider('schemaFormDecorators',
876891

877892

878893
/**
894+
* DEPRECATED use defineAddOn() instead.
879895
* Adds a mapping to an existing decorator.
880896
* @param {String} name Decorator name
881897
* @param {String} type Form type for the mapping
@@ -893,6 +909,25 @@ angular.module('schemaForm').provider('schemaFormDecorators',
893909
}
894910
};
895911

912+
/**
913+
* Adds an add-on to an existing decorator.
914+
* @param {String} name Decorator name
915+
* @param {String} type Form type for the mapping
916+
* @param {String} url The template url
917+
* @param {Function|Array} builder (optional) builder function(s),
918+
*/
919+
this.defineAddOn = function(name, type, url, builder) {
920+
if (decorators[name]) {
921+
decorators[name][type] = {
922+
template: url,
923+
builder: builder,
924+
replace: true
925+
};
926+
}
927+
};
928+
929+
930+
896931
//Service is just a getter for directive templates and rules
897932
this.$get = function() {
898933
return {
@@ -1817,11 +1852,27 @@ angular.module('schemaForm').directive('sfArray', ['sfSelect', 'schemaForm', 'sf
18171852
scope.$on('schemaFormValidate', scope.validateArray);
18181853

18191854
scope.hasSuccess = function() {
1820-
return ngModel.$valid && !ngModel.$pristine;
1855+
if (scope.options && scope.options.pristine &&
1856+
scope.options.pristine.success === false) {
1857+
return ngModel.$valid &&
1858+
!ngModel.$pristine && !ngModel.$isEmpty(ngModel.$modelValue);
1859+
} else {
1860+
return ngModel.$valid &&
1861+
(!ngModel.$pristine || !ngModel.$isEmpty(ngModel.$modelValue));
1862+
}
18211863
};
18221864

18231865
scope.hasError = function() {
1824-
return ngModel.$invalid;
1866+
if (!scope.options || !scope.options.pristine || scope.options.pristine.errors !== false) {
1867+
// Show errors in pristine forms. The default.
1868+
// Note that "validateOnRender" option defaults to *not* validate initial form.
1869+
// so as a default there won't be any error anyway, but if the model is modified
1870+
// from the outside the error will show even if the field is pristine.
1871+
return ngModel.$invalid;
1872+
} else {
1873+
// Don't show errors in pristine forms.
1874+
return ngModel.$invalid && !ngModel.$pristine;
1875+
}
18251876
};
18261877

18271878
scope.schemaError = function() {
@@ -1975,20 +2026,35 @@ angular.module('schemaForm').directive('sfField',
19752026
return (expression && $interpolate(expression)(locals));
19762027
};
19772028

1978-
//This works since we ot the ngModel from the array or the schema-validate directive.
2029+
//This works since we get the ngModel from the array or the schema-validate directive.
19792030
scope.hasSuccess = function() {
19802031
if (!scope.ngModel) {
19812032
return false;
19822033
}
1983-
return scope.ngModel.$valid &&
2034+
if (scope.options && scope.options.pristine &&
2035+
scope.options.pristine.success === false) {
2036+
return scope.ngModel.$valid &&
2037+
!scope.ngModel.$pristine && !scope.ngModel.$isEmpty(scope.ngModel.$modelValue);
2038+
} else {
2039+
return scope.ngModel.$valid &&
19842040
(!scope.ngModel.$pristine || !scope.ngModel.$isEmpty(scope.ngModel.$modelValue));
2041+
}
19852042
};
19862043

19872044
scope.hasError = function() {
19882045
if (!scope.ngModel) {
19892046
return false;
19902047
}
1991-
return scope.ngModel.$invalid && !scope.ngModel.$pristine;
2048+
if (!scope.options || !scope.options.pristine || scope.options.pristine.errors !== false) {
2049+
// Show errors in pristine forms. The default.
2050+
// Note that "validateOnRender" option defaults to *not* validate initial form.
2051+
// so as a default there won't be any error anyway, but if the model is modified
2052+
// from the outside the error will show even if the field is pristine.
2053+
return scope.ngModel.$invalid;
2054+
} else {
2055+
// Don't show errors in pristine forms.
2056+
return scope.ngModel.$invalid && !scope.ngModel.$pristine;
2057+
}
19922058
};
19932059

19942060
/**
@@ -2046,7 +2112,8 @@ angular.module('schemaForm').directive('sfField',
20462112
scope.$broadcast('schemaFormValidate');
20472113
}
20482114
}
2049-
});
2115+
}
2116+
);
20502117

20512118
// Clean up the model when the corresponding form field is $destroy-ed.
20522119
// Default behavior can be supplied as a globalOption, and behavior can be overridden
@@ -2113,60 +2180,80 @@ angular.module('schemaForm').directive('sfMessage',
21132180
scope.$watch(attrs.sfMessage, function(msg) {
21142181
if (msg) {
21152182
message = $sanitize(msg);
2116-
if (scope.ngModel) {
2117-
update(scope.ngModel.$valid);
2118-
} else {
2119-
update();
2120-
}
2183+
update(!!scope.ngModel);
21212184
}
21222185
});
21232186
}
21242187

2125-
var update = function(valid) {
2126-
if (valid && !scope.hasError()) {
2127-
element.html(message);
2128-
} else {
2129-
var errors = [];
2130-
angular.forEach(((scope.ngModel && scope.ngModel.$error) || {}), function(status, code) {
2131-
if (status) {
2132-
// if true then there is an error
2133-
// Angular 1.3 removes properties, so we will always just have errors.
2134-
// Angular 1.2 sets them to false.
2135-
errors.push(code);
2136-
}
2137-
});
2188+
var currentMessage;
2189+
// Only call html() if needed.
2190+
var setMessage = function(msg) {
2191+
if (msg !== currentMessage) {
2192+
element.html(msg);
2193+
currentMessage = msg;
2194+
}
2195+
};
21382196

2139-
// In Angular 1.3 we use one $validator to stop the model value from getting updated.
2140-
// this means that we always end up with a 'schemaForm' error.
2141-
errors = errors.filter(function(e) { return e !== 'schemaForm'; });
2142-
2143-
// We only show one error.
2144-
// TODO: Make that optional
2145-
var error = errors[0];
2146-
2147-
if (error) {
2148-
element.html(sfErrorMessage.interpolate(
2149-
error,
2150-
scope.ngModel.$modelValue,
2151-
scope.ngModel.$viewValue,
2152-
scope.form,
2153-
scope.options && scope.options.validationMessage
2154-
));
2197+
var update = function(checkForErrors) {
2198+
if (checkForErrors) {
2199+
if (!scope.hasError()) {
2200+
setMessage(message);
21552201
} else {
2156-
element.html(message);
2202+
var errors = [];
2203+
angular.forEach(scope.ngModel && scope.ngModel.$error, function(status, code) {
2204+
if (status) {
2205+
// if true then there is an error
2206+
// Angular 1.3 removes properties, so we will always just have errors.
2207+
// Angular 1.2 sets them to false.
2208+
errors.push(code);
2209+
}
2210+
});
2211+
2212+
// In Angular 1.3 we use one $validator to stop the model value from getting updated.
2213+
// this means that we always end up with a 'schemaForm' error.
2214+
errors = errors.filter(function(e) { return e !== 'schemaForm'; });
2215+
2216+
// We only show one error.
2217+
// TODO: Make that optional
2218+
var error = errors[0];
2219+
2220+
if (error) {
2221+
setMessage(sfErrorMessage.interpolate(
2222+
error,
2223+
scope.ngModel.$modelValue,
2224+
scope.ngModel.$viewValue,
2225+
scope.form,
2226+
scope.options && scope.options.validationMessage
2227+
));
2228+
} else {
2229+
setMessage(message);
2230+
}
21572231
}
2232+
} else {
2233+
setMessage(message);
21582234
}
21592235
};
21602236

21612237
// Update once.
21622238
update();
21632239

2164-
scope.$watchCollection('ngModel.$error', function() {
2165-
if (scope.ngModel) {
2166-
update(scope.ngModel.$valid);
2240+
var once = scope.$watch('ngModel',function(ngModel) {
2241+
if (ngModel) {
2242+
// We also listen to changes of the model via parsers and formatters.
2243+
// This is since both the error message can change and given a pristine
2244+
// option to not show errors the ngModel.$error might not have changed
2245+
// but we're not pristine any more so we should change!
2246+
ngModel.$parsers.push(function(val) { update(true); return val; });
2247+
ngModel.$formatters.push(function(val) { update(true); return val; });
2248+
once();
21672249
}
21682250
});
21692251

2252+
// We watch for changes in $error
2253+
scope.$watchCollection('ngModel.$error', function() {
2254+
update(!!scope.ngModel);
2255+
});
2256+
21702257
}
21712258
};
21722259
}]);
@@ -2627,11 +2714,13 @@ angular.module('schemaForm').directive('schemaValidate', ['sfValidator', '$parse
26272714
sfSelect(path, scope.model, ngModel.$modelValue);
26282715
});
26292716
});
2630-
}
2717+
};
2718+
26312719

26322720
// Validate against the schema.
26332721

26342722
var validate = function(viewValue) {
2723+
//console.log('validate called', viewValue)
26352724
//Still might be undefined
26362725
if (!form) {
26372726
return viewValue;
@@ -2643,7 +2732,7 @@ angular.module('schemaForm').directive('schemaValidate', ['sfValidator', '$parse
26432732
}
26442733

26452734
var result = sfValidator.validate(form, viewValue);
2646-
2735+
//console.log('result is', result)
26472736
// Since we might have different tv4 errors we must clear all
26482737
// errors that start with tv4-
26492738
Object.keys(ngModel.$error)
@@ -2698,6 +2787,7 @@ angular.module('schemaForm').directive('schemaValidate', ['sfValidator', '$parse
26982787
// updating if we've found an error.
26992788
if (ngModel.$validators) {
27002789
ngModel.$validators.schemaForm = function() {
2790+
//console.log('validators called.')
27012791
// Any error and we're out of here!
27022792
return !Object.keys(ngModel.$error).some(function(e) { return e !== 'schemaForm';});
27032793
};
@@ -2741,6 +2831,20 @@ angular.module('schemaForm').directive('schemaValidate', ['sfValidator', '$parse
27412831
}
27422832
};
27432833

2834+
var first = true;
2835+
ngModel.$formatters.push(function(val) {
2836+
2837+
// When a form first loads this will be called for each field.
2838+
// we usually don't want that.
2839+
if (ngModel.$pristine && first &&
2840+
(!scope.options || scope.options.validateOnRender !== true)) {
2841+
first = false;
2842+
return val;
2843+
}
2844+
validate(ngModel.$modelValue);
2845+
return val;
2846+
});
2847+
27442848
// Listen to an event so we can validate the input on request
27452849
scope.$on('schemaFormValidate', scope.validateField);
27462850

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: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -198,13 +198,15 @@ attribute which should be placed along side `sf-schema`.
198198
`sf-options` takes an object with the following possible attributes.
199199
200200
201-
| Attribute | |
202-
|:--------------|:------------------------|
203-
| supressPropertyTitles | by default schema form uses the property name in the schema as a title if none is specified, set this to true to disable that behavior |
204-
| formDefaults | an object that will be used as a default for all form definitions |
205-
| validationMessage | an object or a function that will be used as default validation message for all fields. See [Validation Messages](#validation-messages) for details. |
206-
| setSchemaDefaults | boolean, set to false an no defaults from the schema will be set on the model. |
207-
| destroyStrategy | the default strategy to use for cleaning the model when a form element is removed. see [destroyStrategy](#destroyStrategy) below |
201+
| Attribute | Type | |
202+
|:--------------|:------|:-------------------|
203+
| supressPropertyTitles | boolean |by default schema form uses the property name in the schema as a title if none is specified, set this to true to disable that behavior |
204+
| formDefaults | object | an object that will be used as a default for all form definitions |
205+
| validationMessage | object or function | Object or a function that will be used as default validation message for all fields. See [Validation Messages](#validation-messages) for details. |
206+
| setSchemaDefaults | boolean | Should schema defaults be set on model. |
207+
| destroyStrategy | string | the default strategy to use for cleaning the model when a form element is removed. see [destroyStrategy](#destroyStrategy) below |
208+
| pristine | Object `{errors ,success}` | Sets if errors and success states should be visible when form field are `$pristine`. Default is `{errors: true, success: true}` |
209+
| validateOnRender | boolean | Should form be validated on initial render? Default `false` |
208210
209211
*formDefaults* is mostly useful for setting global [ngModelOptions](#ngmodeloptions)
210212
i.e. changing the entire form to validate on blur.

0 commit comments

Comments
 (0)