@@ -299,6 +299,13 @@ angular.module('schemaForm').provider('sfBuilder', ['sfPathProvider', function(s
299
299
}
300
300
} ;
301
301
this . builders = builders ;
302
+ var stdBuilders = [
303
+ builders . sfField ,
304
+ builders . ngModel ,
305
+ builders . ngModelOptions ,
306
+ builders . condition
307
+ ] ;
308
+ this . stdBuilders = stdBuilders ;
302
309
303
310
this . $get = [ '$templateCache' , 'schemaFormDecorators' , 'sfPath' , function ( $templateCache , schemaFormDecorators , sfPath ) {
304
311
@@ -326,7 +333,7 @@ angular.module('schemaForm').provider('sfBuilder', ['sfPathProvider', function(s
326
333
327
334
// Sanity check.
328
335
if ( ! f . type ) {
329
- return ;
336
+ return frag ;
330
337
}
331
338
332
339
var field = decorator [ f . type ] || decorator [ 'default' ] ;
@@ -408,6 +415,7 @@ angular.module('schemaForm').provider('sfBuilder', ['sfPathProvider', function(s
408
415
409
416
} ,
410
417
builder : builders ,
418
+ stdBuilders : stdBuilders ,
411
419
internalBuild : build
412
420
} ;
413
421
} ] ;
@@ -812,17 +820,22 @@ angular.module('schemaForm').provider('schemaFormDecorators',
812
820
813
821
814
822
/**
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.
819
825
*
820
- * ex. Basic usage
821
- * <sf-decorator form="myform"></sf-decorator>
822
- **
823
826
* @param {string } name directive name (CamelCased)
824
827
* @param {Object } fields, an object that maps "type" => `{ template, builder, replace}`.
825
828
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.
826
839
*/
827
840
this . defineDecorator = function ( name , fields ) {
828
841
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',
840
853
} ;
841
854
842
855
/**
856
+ * DEPRECATED
843
857
* Creates a directive of a decorator
844
858
* Usable when you want to use the decorators without using <schema-form> directive.
845
859
* Specifically when you need to reuse styling.
@@ -854,6 +868,7 @@ angular.module('schemaForm').provider('schemaFormDecorators',
854
868
this . createDirective = createManualDirective ;
855
869
856
870
/**
871
+ * DEPRECATED
857
872
* Same as createDirective, but takes an object where key is 'type' and value is 'templateUrl'
858
873
* Useful for batching.
859
874
* @param {Object } templates
@@ -876,6 +891,7 @@ angular.module('schemaForm').provider('schemaFormDecorators',
876
891
877
892
878
893
/**
894
+ * DEPRECATED use defineAddOn() instead.
879
895
* Adds a mapping to an existing decorator.
880
896
* @param {String } name Decorator name
881
897
* @param {String } type Form type for the mapping
@@ -893,6 +909,25 @@ angular.module('schemaForm').provider('schemaFormDecorators',
893
909
}
894
910
} ;
895
911
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
+
896
931
//Service is just a getter for directive templates and rules
897
932
this . $get = function ( ) {
898
933
return {
@@ -1817,11 +1852,27 @@ angular.module('schemaForm').directive('sfArray', ['sfSelect', 'schemaForm', 'sf
1817
1852
scope . $on ( 'schemaFormValidate' , scope . validateArray ) ;
1818
1853
1819
1854
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
+ }
1821
1863
} ;
1822
1864
1823
1865
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
+ }
1825
1876
} ;
1826
1877
1827
1878
scope . schemaError = function ( ) {
@@ -1975,20 +2026,35 @@ angular.module('schemaForm').directive('sfField',
1975
2026
return ( expression && $interpolate ( expression ) ( locals ) ) ;
1976
2027
} ;
1977
2028
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.
1979
2030
scope . hasSuccess = function ( ) {
1980
2031
if ( ! scope . ngModel ) {
1981
2032
return false ;
1982
2033
}
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 &&
1984
2040
( ! scope . ngModel . $pristine || ! scope . ngModel . $isEmpty ( scope . ngModel . $modelValue ) ) ;
2041
+ }
1985
2042
} ;
1986
2043
1987
2044
scope . hasError = function ( ) {
1988
2045
if ( ! scope . ngModel ) {
1989
2046
return false ;
1990
2047
}
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
+ }
1992
2058
} ;
1993
2059
1994
2060
/**
@@ -2046,7 +2112,8 @@ angular.module('schemaForm').directive('sfField',
2046
2112
scope . $broadcast ( 'schemaFormValidate' ) ;
2047
2113
}
2048
2114
}
2049
- } ) ;
2115
+ }
2116
+ ) ;
2050
2117
2051
2118
// Clean up the model when the corresponding form field is $destroy-ed.
2052
2119
// Default behavior can be supplied as a globalOption, and behavior can be overridden
@@ -2113,60 +2180,80 @@ angular.module('schemaForm').directive('sfMessage',
2113
2180
scope . $watch ( attrs . sfMessage , function ( msg ) {
2114
2181
if ( msg ) {
2115
2182
message = $sanitize ( msg ) ;
2116
- if ( scope . ngModel ) {
2117
- update ( scope . ngModel . $valid ) ;
2118
- } else {
2119
- update ( ) ;
2120
- }
2183
+ update ( ! ! scope . ngModel ) ;
2121
2184
}
2122
2185
} ) ;
2123
2186
}
2124
2187
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
+ } ;
2138
2196
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 ) ;
2155
2201
} 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
+ }
2157
2231
}
2232
+ } else {
2233
+ setMessage ( message ) ;
2158
2234
}
2159
2235
} ;
2160
2236
2161
2237
// Update once.
2162
2238
update ( ) ;
2163
2239
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 ( ) ;
2167
2249
}
2168
2250
} ) ;
2169
2251
2252
+ // We watch for changes in $error
2253
+ scope . $watchCollection ( 'ngModel.$error' , function ( ) {
2254
+ update ( ! ! scope . ngModel ) ;
2255
+ } ) ;
2256
+
2170
2257
}
2171
2258
} ;
2172
2259
} ] ) ;
@@ -2627,11 +2714,13 @@ angular.module('schemaForm').directive('schemaValidate', ['sfValidator', '$parse
2627
2714
sfSelect ( path , scope . model , ngModel . $modelValue ) ;
2628
2715
} ) ;
2629
2716
} ) ;
2630
- }
2717
+ } ;
2718
+
2631
2719
2632
2720
// Validate against the schema.
2633
2721
2634
2722
var validate = function ( viewValue ) {
2723
+ //console.log('validate called', viewValue)
2635
2724
//Still might be undefined
2636
2725
if ( ! form ) {
2637
2726
return viewValue ;
@@ -2643,7 +2732,7 @@ angular.module('schemaForm').directive('schemaValidate', ['sfValidator', '$parse
2643
2732
}
2644
2733
2645
2734
var result = sfValidator . validate ( form , viewValue ) ;
2646
-
2735
+ //console.log('result is', result)
2647
2736
// Since we might have different tv4 errors we must clear all
2648
2737
// errors that start with tv4-
2649
2738
Object . keys ( ngModel . $error )
@@ -2698,6 +2787,7 @@ angular.module('schemaForm').directive('schemaValidate', ['sfValidator', '$parse
2698
2787
// updating if we've found an error.
2699
2788
if ( ngModel . $validators ) {
2700
2789
ngModel . $validators . schemaForm = function ( ) {
2790
+ //console.log('validators called.')
2701
2791
// Any error and we're out of here!
2702
2792
return ! Object . keys ( ngModel . $error ) . some ( function ( e ) { return e !== 'schemaForm' ; } ) ;
2703
2793
} ;
@@ -2741,6 +2831,20 @@ angular.module('schemaForm').directive('schemaValidate', ['sfValidator', '$parse
2741
2831
}
2742
2832
} ;
2743
2833
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
+
2744
2848
// Listen to an event so we can validate the input on request
2745
2849
scope . $on ( 'schemaFormValidate' , scope . validateField ) ;
2746
2850
0 commit comments