@@ -168,8 +168,10 @@ angular.module('schemaForm').provider('schemaFormDecorators',
168
168
169
169
var createDirective = function ( name ) {
170
170
$compileProvider . directive ( name ,
171
- [ '$parse' , '$compile' , '$http' , '$templateCache' , '$interpolate' , '$q' , 'sfErrorMessage' , 'sfPath' ,
172
- function ( $parse , $compile , $http , $templateCache , $interpolate , $q , sfErrorMessage , sfPath ) {
171
+ [ '$parse' , '$compile' , '$http' , '$templateCache' , '$interpolate' , '$q' , 'sfErrorMessage' ,
172
+ 'sfPath' , 'sfSelect' ,
173
+ function ( $parse , $compile , $http , $templateCache , $interpolate , $q , sfErrorMessage ,
174
+ sfPath , sfSelect ) {
173
175
174
176
return {
175
177
restrict : 'AE' ,
@@ -398,7 +400,48 @@ angular.module('schemaForm').provider('schemaFormDecorators',
398
400
scope . $broadcast ( 'schemaFormValidate' ) ;
399
401
}
400
402
}
401
- } )
403
+ } ) ;
404
+
405
+ // Clean up the model when the corresponding form field is $destroy-ed.
406
+ // Default behavior can be supplied as a globalOption, and behavior can be overridden in the form definition.
407
+ scope . $on ( '$destroy' , function ( ) {
408
+ // If the entire schema form is destroyed we don't touch the model
409
+ if ( ! scope . externalDestructionInProgress ) {
410
+ var destroyStrategy = form . destroyStrategy ||
411
+ ( scope . options && scope . options . destroyStrategy ) || 'remove' ;
412
+ // No key no model, and we might have strategy 'retain'
413
+ if ( form . key && destroyStrategy !== 'retain' ) {
414
+
415
+ // Get the object that has the property we wan't to clear.
416
+ var obj = scope . model ;
417
+ if ( form . key . length > 1 ) {
418
+ obj = sfSelect ( form . key . slice ( 0 , form . key . length - 1 ) , obj ) ;
419
+ }
420
+
421
+ // We can get undefined here if the form hasn't been filled out entirely
422
+ if ( obj === undefined ) {
423
+ return ;
424
+ }
425
+
426
+ // Type can also be a list in JSON Schema
427
+ var type = ( form . schema && form . schema . type ) || '' ;
428
+
429
+ // Empty means '',{} and [] for appropriate types and undefined for the rest
430
+ //console.log('destroy', destroyStrategy, form.key, type, obj);
431
+ if ( destroyStrategy === 'empty' && type . indexOf ( 'string' ) !== - 1 ) {
432
+ obj [ form . key . slice ( - 1 ) ] = '' ;
433
+ } else if ( destroyStrategy === 'empty' && type . indexOf ( 'object' ) !== - 1 ) {
434
+ obj [ form . key . slice ( - 1 ) ] = { } ;
435
+ } else if ( destroyStrategy === 'empty' && type . indexOf ( 'array' ) !== - 1 ) {
436
+ obj [ form . key . slice ( - 1 ) ] = [ ] ;
437
+ } else if ( destroyStrategy === 'null' ) {
438
+ obj [ form . key . slice ( - 1 ) ] = null ;
439
+ } else {
440
+ delete obj [ form . key . slice ( - 1 ) ] ;
441
+ }
442
+ }
443
+ }
444
+ } ) ;
402
445
}
403
446
404
447
once ( ) ;
@@ -1633,7 +1676,10 @@ angular.module('schemaForm')
1633
1676
// they have been removed from the DOM
1634
1677
// https://github.com/Textalk/angular-schema-form/issues/200
1635
1678
if ( childScope ) {
1679
+ // Destroy strategy should not be acted upon
1680
+ scope . externalDestructionInProgress = true ;
1636
1681
childScope . $destroy ( ) ;
1682
+ scope . externalDestructionInProgress = false ;
1637
1683
}
1638
1684
childScope = scope . $new ( ) ;
1639
1685
@@ -1680,14 +1726,16 @@ angular.module('schemaForm')
1680
1726
$compile ( element . children ( ) ) ( childScope ) ;
1681
1727
1682
1728
//ok, now that that is done let's set any defaults
1683
- schemaForm . traverseSchema ( schema , function ( prop , path ) {
1684
- if ( angular . isDefined ( prop [ 'default' ] ) ) {
1685
- var val = sfSelect ( path , scope . model ) ;
1686
- if ( angular . isUndefined ( val ) ) {
1687
- sfSelect ( path , scope . model , prop [ 'default' ] ) ;
1729
+ if ( ! scope . options || scope . options . setSchemaDefaults !== false ) {
1730
+ schemaForm . traverseSchema ( schema , function ( prop , path ) {
1731
+ if ( angular . isDefined ( prop [ 'default' ] ) ) {
1732
+ var val = sfSelect ( path , scope . model ) ;
1733
+ if ( angular . isUndefined ( val ) ) {
1734
+ sfSelect ( path , scope . model , prop [ 'default' ] ) ;
1735
+ }
1688
1736
}
1689
- }
1690
- } ) ;
1737
+ } ) ;
1738
+ }
1691
1739
1692
1740
scope . $emit ( 'sf-render-finished' , element ) ;
1693
1741
} ;
@@ -1720,121 +1768,131 @@ angular.module('schemaForm')
1720
1768
}
1721
1769
} ) ;
1722
1770
1771
+ scope . $on ( '$destroy' , function ( ) {
1772
+ // Each field listens to the $destroy event so that it can remove any value
1773
+ // from the model if that field is removed from the form. This is the default
1774
+ // destroy strategy. But if the entire form (or at least the part we're on)
1775
+ // gets removed, like when routing away to another page, then we definetly want to
1776
+ // keep the model intact. So therefore we set a flag to tell the others it's time to just
1777
+ // let it be.
1778
+ scope . externalDestructionInProgress = true ;
1779
+ } ) ;
1723
1780
}
1724
1781
} ;
1725
1782
}
1726
1783
] ) ;
1727
1784
1728
- angular . module ( 'schemaForm' ) . directive ( 'schemaValidate' , [ 'sfValidator' , 'sfSelect' , function ( sfValidator , sfSelect ) {
1729
- return {
1730
- restrict : 'A' ,
1731
- scope : false ,
1732
- // We want the link function to be *after* the input directives link function so we get access
1733
- // the parsed value, ex. a number instead of a string
1734
- priority : 500 ,
1735
- require : 'ngModel' ,
1736
- link : function ( scope , element , attrs , ngModel ) {
1785
+ angular . module ( 'schemaForm' ) . directive ( 'schemaValidate' , [ 'sfValidator' , '$parse' ,
1786
+ function ( sfValidator , $parse ) {
1737
1787
1788
+ return {
1789
+ restrict : 'A' ,
1790
+ scope : false ,
1791
+ // We want the link function to be *after* the input directives link function so we get access
1792
+ // the parsed value, ex. a number instead of a string
1793
+ priority : 500 ,
1794
+ require : 'ngModel' ,
1795
+ link : function ( scope , element , attrs , ngModel ) {
1738
1796
1739
- // We need the ngModelController on several places,
1740
- // most notably for errors.
1741
- // So we emit it up to the decorator directive so it can put it on scope.
1742
- scope . $emit ( 'schemaFormPropagateNgModelController' , ngModel ) ;
1797
+ // We need the ngModelController on several places,
1798
+ // most notably for errors.
1799
+ // So we emit it up to the decorator directive so it can put it on scope.
1800
+ scope . $emit ( 'schemaFormPropagateNgModelController' , ngModel ) ;
1743
1801
1744
- var error = null ;
1802
+ var error = null ;
1745
1803
1746
- var getForm = function ( ) {
1747
- if ( ! form ) {
1748
- form = scope . $eval ( attrs . schemaValidate ) ;
1749
- }
1750
- return form ;
1751
- } ;
1752
- var form = getForm ( ) ;
1753
- if ( form . copyValueTo ) {
1754
- ngModel . $viewChangeListeners . push ( function ( ) {
1755
- var paths = form . copyValueTo ;
1756
- angular . forEach ( paths , function ( path ) {
1757
- sfSelect ( path , scope . model , ngModel . $modelValue ) ;
1804
+ var getForm = function ( ) {
1805
+ if ( ! form ) {
1806
+ form = scope . $eval ( attrs . schemaValidate ) ;
1807
+ }
1808
+ return form ;
1809
+ } ;
1810
+ var form = getForm ( ) ;
1811
+ if ( form . copyValueTo ) {
1812
+ ngModel . $viewChangeListeners . push ( function ( ) {
1813
+ var paths = form . copyValueTo ;
1814
+ angular . forEach ( paths , function ( path ) {
1815
+ sfSelect ( path , scope . model , ngModel . $modelValue ) ;
1816
+ } ) ;
1758
1817
} ) ;
1759
- } ) ;
1760
- }
1818
+ }
1761
1819
1762
- // Validate against the schema.
1820
+ // Validate against the schema.
1763
1821
1764
- var validate = function ( viewValue ) {
1765
- form = getForm ( ) ;
1766
- //Still might be undefined
1767
- if ( ! form ) {
1768
- return viewValue ;
1769
- }
1822
+ var validate = function ( viewValue ) {
1823
+ form = getForm ( ) ;
1824
+ //Still might be undefined
1825
+ if ( ! form ) {
1826
+ return viewValue ;
1827
+ }
1770
1828
1771
- // Omit TV4 validation
1772
- if ( scope . options && scope . options . tv4Validation === false ) {
1773
- return viewValue ;
1774
- }
1829
+ // Omit TV4 validation
1830
+ if ( scope . options && scope . options . tv4Validation === false ) {
1831
+ return viewValue ;
1832
+ }
1775
1833
1776
- var result = sfValidator . validate ( form , viewValue ) ;
1777
- // Since we might have different tv4 errors we must clear all
1778
- // errors that start with tv4-
1779
- Object . keys ( ngModel . $error )
1834
+ var result = sfValidator . validate ( form , viewValue ) ;
1835
+ // Since we might have different tv4 errors we must clear all
1836
+ // errors that start with tv4-
1837
+ Object . keys ( ngModel . $error )
1780
1838
. filter ( function ( k ) { return k . indexOf ( 'tv4-' ) === 0 ; } )
1781
1839
. forEach ( function ( k ) { ngModel . $setValidity ( k , true ) ; } ) ;
1782
1840
1783
- if ( ! result . valid ) {
1784
- // it is invalid, return undefined (no model update)
1785
- ngModel . $setValidity ( 'tv4-' + result . error . code , false ) ;
1786
- error = result . error ;
1787
- return undefined ;
1788
- }
1789
- return viewValue ;
1790
- } ;
1791
-
1792
- // Custom validators, parsers, formatters etc
1793
- if ( typeof form . ngModel === 'function' ) {
1794
- form . ngModel ( ngModel ) ;
1795
- }
1841
+ if ( ! result . valid ) {
1842
+ // it is invalid, return undefined (no model update)
1843
+ ngModel . $setValidity ( 'tv4-' + result . error . code , false ) ;
1844
+ error = result . error ;
1845
+ return undefined ;
1846
+ }
1847
+ return viewValue ;
1848
+ } ;
1796
1849
1797
- [ '$parsers' , '$viewChangeListeners' , '$formatters' ] . forEach ( function ( attr ) {
1798
- if ( form [ attr ] && ngModel [ attr ] ) {
1799
- form [ attr ] . forEach ( function ( fn ) {
1800
- ngModel [ attr ] . push ( fn ) ;
1801
- } ) ;
1850
+ // Custom validators, parsers, formatters etc
1851
+ if ( typeof form . ngModel === 'function' ) {
1852
+ form . ngModel ( ngModel ) ;
1802
1853
}
1803
- } ) ;
1804
1854
1805
- [ '$validators' , '$asyncValidators' ] . forEach ( function ( attr ) {
1806
- // Check if our version of angular has i, i.e. 1.3+
1807
- if ( form [ attr ] && ngModel [ attr ] ) {
1808
- angular . forEach ( form [ attr ] , function ( fn , name ) {
1809
- ngModel [ attr ] [ name ] = fn ;
1810
- } ) ;
1811
- }
1812
- } ) ;
1855
+ [ '$parsers' , '$viewChangeListeners' , '$formatters' ] . forEach ( function ( attr ) {
1856
+ if ( form [ attr ] && ngModel [ attr ] ) {
1857
+ form [ attr ] . forEach ( function ( fn ) {
1858
+ ngModel [ attr ] . push ( fn ) ;
1859
+ } ) ;
1860
+ }
1861
+ } ) ;
1813
1862
1814
- // Get in last of the parses so the parsed value has the correct type.
1815
- // We don't use $validators since we like to set different errors depeding tv4 error codes
1816
- ngModel . $parsers . push ( validate ) ;
1863
+ [ '$validators' , '$asyncValidators' ] . forEach ( function ( attr ) {
1864
+ // Check if our version of angular has i, i.e. 1.3+
1865
+ if ( form [ attr ] && ngModel [ attr ] ) {
1866
+ angular . forEach ( form [ attr ] , function ( fn , name ) {
1867
+ ngModel [ attr ] [ name ] = fn ;
1868
+ } ) ;
1869
+ }
1870
+ } ) ;
1817
1871
1818
- // Listen to an event so we can validate the input on request
1819
- scope . $on ( 'schemaFormValidate' , function ( ) {
1820
- if ( ngModel . $setDirty ) {
1821
- // Angular 1.3+
1822
- ngModel . $setDirty ( ) ;
1823
- validate ( ngModel . $modelValue ) ;
1824
- } else {
1825
- // Angular 1.2
1826
- ngModel . $setViewValue ( ngModel . $viewValue ) ;
1827
- }
1872
+ // Get in last of the parses so the parsed value has the correct type.
1873
+ // We don't use $validators since we like to set different errors depeding tv4 error codes
1874
+ ngModel . $parsers . push ( validate ) ;
1828
1875
1829
- } ) ;
1876
+ // Listen to an event so we can validate the input on request
1877
+ scope . $on ( 'schemaFormValidate' , function ( ) {
1878
+ if ( ngModel . $setDirty ) {
1879
+ // Angular 1.3+
1880
+ ngModel . $setDirty ( ) ;
1881
+ validate ( ngModel . $modelValue ) ;
1882
+ } else {
1883
+ // Angular 1.2
1884
+ ngModel . $setViewValue ( ngModel . $viewValue ) ;
1885
+ }
1830
1886
1831
- scope . schemaError = function ( ) {
1832
- return error ;
1833
- } ;
1887
+ } ) ;
1834
1888
1835
- }
1836
- } ;
1837
- } ] ) ;
1889
+ scope . schemaError = function ( ) {
1890
+ return error ;
1891
+ } ;
1892
+
1893
+ }
1894
+ } ;
1895
+ } ] ) ;
1838
1896
1839
1897
return schemaForm ;
1840
1898
} ) ) ;
0 commit comments