@@ -65,6 +65,81 @@ angular.module('schemaForm').provider('sfPath',
65
65
} ;
66
66
} ] ) ;
67
67
68
+ /**
69
+ * @ngdoc service
70
+ * @name sfSelect
71
+ * @kind function
72
+ *
73
+ */
74
+ angular . module ( 'schemaForm' ) . factory ( 'sfSelect' , [ 'sfPath' , function ( sfPath ) {
75
+ var numRe = / ^ \d + $ / ;
76
+
77
+ /**
78
+ * @description
79
+ * Utility method to access deep properties without
80
+ * throwing errors when things are not defined.
81
+ * Can also set a value in a deep structure, creating objects when missing
82
+ * ex.
83
+ * var foo = Select('address.contact.name',obj)
84
+ * Select('address.contact.name',obj,'Leeroy')
85
+ *
86
+ * @param {string } projection A dot path to the property you want to get/set
87
+ * @param {object } obj (optional) The object to project on, defaults to 'this'
88
+ * @param {Any } valueToSet (opional) The value to set, if parts of the path of
89
+ * the projection is missing empty objects will be created.
90
+ * @returns {Any|undefined } returns the value at the end of the projection path
91
+ * or undefined if there is none.
92
+ */
93
+ return function ( projection , obj , valueToSet ) {
94
+ if ( ! obj ) {
95
+ obj = this ;
96
+ }
97
+ //Support [] array syntax
98
+ var parts = typeof projection === 'string' ? sfPath . parse ( projection ) : projection ;
99
+
100
+ if ( typeof valueToSet !== 'undefined' && parts . length === 1 ) {
101
+ //special case, just setting one variable
102
+ obj [ parts [ 0 ] ] = valueToSet ;
103
+ return obj ;
104
+ }
105
+
106
+ if ( typeof valueToSet !== 'undefined' &&
107
+ typeof obj [ parts [ 0 ] ] === 'undefined' ) {
108
+ // We need to look ahead to check if array is appropriate
109
+ obj [ parts [ 0 ] ] = parts . length > 2 && numRe . test ( parts [ 1 ] ) ? [ ] : { } ;
110
+ }
111
+
112
+ var value = obj [ parts [ 0 ] ] ;
113
+ for ( var i = 1 ; i < parts . length ; i ++ ) {
114
+ // Special case: We allow JSON Form syntax for arrays using empty brackets
115
+ // These will of course not work here so we exit if they are found.
116
+ if ( parts [ i ] === '' ) {
117
+ return undefined ;
118
+ }
119
+ if ( typeof valueToSet !== 'undefined' ) {
120
+ if ( i === parts . length - 1 ) {
121
+ //last step. Let's set the value
122
+ value [ parts [ i ] ] = valueToSet ;
123
+ return valueToSet ;
124
+ } else {
125
+ // Make sure to create new objects on the way if they are not there.
126
+ // We need to look ahead to check if array is appropriate
127
+ var tmp = value [ parts [ i ] ] ;
128
+ if ( typeof tmp === 'undefined' || tmp === null ) {
129
+ tmp = numRe . test ( parts [ i + 1 ] ) ? [ ] : { } ;
130
+ value [ parts [ i ] ] = tmp ;
131
+ }
132
+ value = tmp ;
133
+ }
134
+ } else if ( value ) {
135
+ //Just get nex value.
136
+ value = value [ parts [ i ] ] ;
137
+ }
138
+ }
139
+ return value ;
140
+ } ;
141
+ } ] ) ;
142
+
68
143
69
144
// FIXME: type template (using custom builder)
70
145
angular . module ( 'schemaForm' ) . provider ( 'sfBuilder' , [ 'sfPathProvider' , function ( sfPathProvider ) {
@@ -78,9 +153,19 @@ angular.module('schemaForm').provider('sfBuilder', ['sfPathProvider', function(s
78
153
} ;
79
154
var formId = 0 ;
80
155
156
+ if ( ! ( "firstElementChild" in document . createDocumentFragment ( ) ) ) {
157
+ Object . defineProperty ( DocumentFragment . prototype , "firstElementChild" , {
158
+ get : function ( ) {
159
+ for ( var nodes = this . childNodes , n , i = 0 , l = nodes . length ; i < l ; ++ i )
160
+ if ( n = nodes [ i ] , 1 === n . nodeType ) return n ;
161
+ return null ;
162
+ }
163
+ } ) ;
164
+ }
165
+
81
166
var builders = {
82
167
sfField : function ( args ) {
83
- args . fieldFrag . firstChild . setAttribute ( 'sf-field' , formId ) ;
168
+ args . fieldFrag . firstElementChild . setAttribute ( 'sf-field' , formId ) ;
84
169
85
170
// We use a lookup table for easy access to our form.
86
171
args . lookup [ 'f' + formId ] = args . form ;
@@ -183,24 +268,27 @@ angular.module('schemaForm').provider('sfBuilder', ['sfPathProvider', function(s
183
268
}
184
269
185
270
var children = args . fieldFrag . children || args . fieldFrag . childNodes ;
271
+ var child ;
272
+ var ngIf ;
186
273
for ( var i = 0 ; i < children . length ; i ++ ) {
187
- var child = children [ i ] ;
188
- var ngIf = child . getAttribute ( 'ng-if' ) ;
189
- child . setAttribute (
190
- 'ng-if' ,
191
- ngIf ?
192
- '(' + ngIf +
193
- ') || (' + evalExpr + ')'
194
- : evalExpr
195
- ) ;
274
+ child = children [ i ] ;
275
+ ngIf = false ;
276
+
277
+ if ( child . hasAttribute && child . hasAttribute ( 'ng-if' ) ) {
278
+ ngIf = child . getAttribute ( 'ng-if' ) ;
279
+ } ;
280
+
281
+ if ( child . setAttribute ) {
282
+ child . setAttribute ( 'ng-if' , ngIf ? '(' + ngIf + ') || (' + evalExpr + ')' : evalExpr ) ;
283
+ } ;
196
284
}
197
285
}
198
286
} ,
199
287
array : function ( args ) {
200
288
var items = args . fieldFrag . querySelector ( '[schema-form-array-items]' ) ;
201
289
if ( items ) {
202
290
state = angular . copy ( args . state ) ;
203
- state . keyRedaction = state . keyRedaction || 0 ;
291
+ state . keyRedaction = 0 ;
204
292
state . keyRedaction += args . form . key . length + 1 ;
205
293
206
294
// Special case, an array with just one item in it that is not an object.
@@ -489,8 +577,14 @@ angular.module('schemaForm').provider('schemaFormDecorators',
489
577
if ( ! scope . ngModel ) {
490
578
return false ;
491
579
}
492
- return scope . ngModel . $valid &&
493
- ( ! scope . ngModel . $pristine || ! scope . ngModel . $isEmpty ( scope . ngModel . $modelValue ) ) ;
580
+ if ( scope . options && scope . options . pristine &&
581
+ scope . options . pristine . success === false ) {
582
+ return scope . ngModel . $valid &&
583
+ ( ! scope . ngModel . $pristine && ! scope . ngModel . $isEmpty ( scope . ngModel . $modelValue ) ) ;
584
+ } else {
585
+ return scope . ngModel . $valid &&
586
+ ( ! scope . ngModel . $pristine || ! scope . ngModel . $isEmpty ( scope . ngModel . $modelValue ) ) ;
587
+ }
494
588
} ;
495
589
496
590
scope . hasError = function ( ) {
@@ -580,12 +674,20 @@ angular.module('schemaForm').provider('schemaFormDecorators',
580
674
// It looks better with dot notation.
581
675
scope . $on (
582
676
'schemaForm.error.' + form . key . join ( '.' ) ,
583
- function ( event , error , validationMessage , validity ) {
677
+ function ( event , error , validationMessage , validity , formName ) {
678
+ // validationMessage and validity are mutually exclusive
679
+ formName = validity ;
584
680
if ( validationMessage === true || validationMessage === false ) {
585
681
validity = validationMessage ;
586
682
validationMessage = undefined ;
587
683
}
588
684
685
+ // If we have specified a form name, and this model is not within
686
+ // that form, then leave things be.
687
+ if ( formName != undefined && scope . ngModel . $$parentForm . $name !== formName ) {
688
+ return ;
689
+ }
690
+
589
691
if ( scope . ngModel && error ) {
590
692
if ( scope . ngModel . $setDirty ) {
591
693
scope . ngModel . $setDirty ( ) ;
@@ -1171,6 +1273,7 @@ angular.module('schemaForm').provider('schemaForm',
1171
1273
if ( stripNullType ( schema . type ) === 'object' ) {
1172
1274
var f = stdFormObj ( name , schema , options ) ;
1173
1275
f . type = 'fieldset' ;
1276
+ f . key = options . path ;
1174
1277
f . items = [ ] ;
1175
1278
options . lookup [ sfPathProvider . stringify ( options . path ) ] = f ;
1176
1279
@@ -1389,7 +1492,7 @@ angular.module('schemaForm').provider('schemaForm',
1389
1492
if ( obj . type === 'checkbox' && angular . isUndefined ( obj . schema [ 'default' ] ) ) {
1390
1493
obj . schema [ 'default' ] = false ;
1391
1494
}
1392
-
1495
+
1393
1496
// Special case: template type with tempplateUrl that's needs to be loaded before rendering
1394
1497
// TODO: this is not a clean solution. Maybe something cleaner can be made when $ref support
1395
1498
// is introduced since we need to go async then anyway
@@ -1481,81 +1584,6 @@ angular.module('schemaForm').provider('schemaForm',
1481
1584
1482
1585
} ] ) ;
1483
1586
1484
- /**
1485
- * @ngdoc service
1486
- * @name sfSelect
1487
- * @kind function
1488
- *
1489
- */
1490
- angular . module ( 'schemaForm' ) . factory ( 'sfSelect' , [ 'sfPath' , function ( sfPath ) {
1491
- var numRe = / ^ \d + $ / ;
1492
-
1493
- /**
1494
- * @description
1495
- * Utility method to access deep properties without
1496
- * throwing errors when things are not defined.
1497
- * Can also set a value in a deep structure, creating objects when missing
1498
- * ex.
1499
- * var foo = Select('address.contact.name',obj)
1500
- * Select('address.contact.name',obj,'Leeroy')
1501
- *
1502
- * @param {string } projection A dot path to the property you want to get/set
1503
- * @param {object } obj (optional) The object to project on, defaults to 'this'
1504
- * @param {Any } valueToSet (opional) The value to set, if parts of the path of
1505
- * the projection is missing empty objects will be created.
1506
- * @returns {Any|undefined } returns the value at the end of the projection path
1507
- * or undefined if there is none.
1508
- */
1509
- return function ( projection , obj , valueToSet ) {
1510
- if ( ! obj ) {
1511
- obj = this ;
1512
- }
1513
- //Support [] array syntax
1514
- var parts = typeof projection === 'string' ? sfPath . parse ( projection ) : projection ;
1515
-
1516
- if ( typeof valueToSet !== 'undefined' && parts . length === 1 ) {
1517
- //special case, just setting one variable
1518
- obj [ parts [ 0 ] ] = valueToSet ;
1519
- return obj ;
1520
- }
1521
-
1522
- if ( typeof valueToSet !== 'undefined' &&
1523
- typeof obj [ parts [ 0 ] ] === 'undefined' ) {
1524
- // We need to look ahead to check if array is appropriate
1525
- obj [ parts [ 0 ] ] = parts . length > 2 && numRe . test ( parts [ 1 ] ) ? [ ] : { } ;
1526
- }
1527
-
1528
- var value = obj [ parts [ 0 ] ] ;
1529
- for ( var i = 1 ; i < parts . length ; i ++ ) {
1530
- // Special case: We allow JSON Form syntax for arrays using empty brackets
1531
- // These will of course not work here so we exit if they are found.
1532
- if ( parts [ i ] === '' ) {
1533
- return undefined ;
1534
- }
1535
- if ( typeof valueToSet !== 'undefined' ) {
1536
- if ( i === parts . length - 1 ) {
1537
- //last step. Let's set the value
1538
- value [ parts [ i ] ] = valueToSet ;
1539
- return valueToSet ;
1540
- } else {
1541
- // Make sure to create new objects on the way if they are not there.
1542
- // We need to look ahead to check if array is appropriate
1543
- var tmp = value [ parts [ i ] ] ;
1544
- if ( typeof tmp === 'undefined' || tmp === null ) {
1545
- tmp = numRe . test ( parts [ i + 1 ] ) ? [ ] : { } ;
1546
- value [ parts [ i ] ] = tmp ;
1547
- }
1548
- value = tmp ;
1549
- }
1550
- } else if ( value ) {
1551
- //Just get nex value.
1552
- value = value [ parts [ i ] ] ;
1553
- }
1554
- }
1555
- return value ;
1556
- } ;
1557
- } ] ) ;
1558
-
1559
1587
/* Common code for validating a value against its form and schema definition */
1560
1588
/* global tv4 */
1561
1589
angular . module ( 'schemaForm' ) . factory ( 'sfValidator' , [ function ( ) {
@@ -2085,12 +2113,20 @@ angular.module('schemaForm').directive('sfField',
2085
2113
// It looks better with dot notation.
2086
2114
scope . $on (
2087
2115
'schemaForm.error.' + form . key . join ( '.' ) ,
2088
- function ( event , error , validationMessage , validity ) {
2116
+ function ( event , error , validationMessage , validity , formName ) {
2117
+ // validationMessage and validity are mutually exclusive
2118
+ formName = validity ;
2089
2119
if ( validationMessage === true || validationMessage === false ) {
2090
2120
validity = validationMessage ;
2091
2121
validationMessage = undefined ;
2092
2122
}
2093
2123
2124
+ // If we have specified a form name, and this model is not within
2125
+ // that form, then leave things be.
2126
+ if ( formName != undefined && scope . ngModel . $$parentForm . $name !== formName ) {
2127
+ return ;
2128
+ }
2129
+
2094
2130
if ( scope . ngModel && error ) {
2095
2131
if ( scope . ngModel . $setDirty ) {
2096
2132
scope . ngModel . $setDirty ( ) ;
@@ -2388,15 +2424,12 @@ function(sel, sfPath, schemaForm) {
2388
2424
if ( vals && vals !== old ) {
2389
2425
var arr = getOrCreateModel ( ) ;
2390
2426
2391
- // Apparently the fastest way to clear an array, readable too.
2392
- // http://jsperf.com/array-destroy/32
2393
- while ( arr . length > 0 ) {
2394
- arr . pop ( ) ;
2395
- }
2396
- form . titleMap . forEach ( function ( item , index ) {
2397
- if ( vals [ index ] ) {
2427
+ form . titleMap . forEach ( function ( item , index ) {
2428
+ var arrIndex = arr . indexOf ( item . value ) ;
2429
+ if ( arrIndex === - 1 && vals [ index ] )
2398
2430
arr . push ( item . value ) ;
2399
- }
2431
+ if ( arrIndex !== - 1 && ! vals [ index ] )
2432
+ arr . splice ( arrIndex , 1 ) ;
2400
2433
} ) ;
2401
2434
2402
2435
// Time to validate the rebuilt array.
0 commit comments