@@ -666,26 +666,25 @@ function orEmptyArray(v) {
666
666
} ;
667
667
668
668
} ;
669
-
670
- function applyIncludeExclude ( metadata , outputModel , observable , initialConstraints ) {
669
+ function applyIncludeExclude ( metadata , outputModel , dataModelItem , initialConstraints ) {
671
670
var path = metadata . constraints . excludePath || metadata . constraints . includePath ;
672
671
673
- var currentValue = observable ( ) ;
674
- var selectedSoFar = [ ] ;
675
- outputModel . eachValueForPath ( path , function ( val ) {
676
- if ( _ . isArray ( val ) ) {
677
- selectedSoFar = selectedSoFar . concat ( val ) ;
678
- } else if ( val != null ) {
679
- selectedSoFar . push ( val ) ;
680
- }
681
- } ) ;
672
+ var currentValue = dataModelItem ( ) ;
673
+ var selectedSoFar = outputModel . getModelValuesForPath ( path ) ;
682
674
683
675
if ( metadata . constraints . excludePath ) {
684
- return _ . filter ( initialConstraints , function ( value ) {
676
+ var filteredConstraints = _ . filter ( initialConstraints , function ( value ) {
677
+ // Handle object valued constraints - however the functions are attached after the first call to
678
+ // the computed observable, so we need to guard against that.
679
+ value = _ . isFunction ( dataModelItem . constraintValue ) ? dataModelItem . constraintValue ( value ) : value ;
685
680
var isCurrentSelection = _ . isArray ( currentValue ) ? currentValue . indexOf ( value ) >= 0 : value == currentValue ;
686
- return ( isCurrentSelection || selectedSoFar . indexOf ( value ) < 0 ) ;
681
+ var include = ( isCurrentSelection || selectedSoFar . indexOf ( value ) < 0 ) ;
682
+ return include ;
687
683
} ) ;
684
+ return filteredConstraints ;
688
685
} else {
686
+ // Note that the "includePath" option does not support object (key/value) typed constraints as
687
+ // it needs to collect values from other form selections which won't be object typed.
689
688
var constraints = initialConstraints . concat ( selectedSoFar ) ;
690
689
var currentSelection = _ . isArray ( currentValue ) ? currentValue : [ currentValue ] ;
691
690
for ( var i = 0 ; i < currentSelection . length ; i ++ ) {
@@ -697,9 +696,7 @@ function orEmptyArray(v) {
697
696
698
697
return constraints ;
699
698
}
700
-
701
699
}
702
-
703
700
/**
704
701
* Implements the constraints specified on a single data model item using the "constraints" attribute in the metadata.
705
702
* Also provides access to global configuration and context for components that need it.
@@ -775,7 +772,20 @@ function orEmptyArray(v) {
775
772
valueProperty = metadata . constraints . valueProperty || valueProperty ;
776
773
textProperty = metadata . constraints . textProperty || textProperty ;
777
774
}
778
-
775
+ // These need to be defined before the computed constraint is defined to support correct evaluation
776
+ // of the excludePath function.
777
+ self . constraintValue = function ( constraint ) {
778
+ if ( _ . isObject ( constraint ) ) {
779
+ return constraint [ valueProperty ] ;
780
+ }
781
+ return constraint ;
782
+ } ;
783
+ self . constraintText = function ( constraint ) {
784
+ if ( _ . isObject ( constraint ) ) {
785
+ return constraint [ textProperty ] ;
786
+ }
787
+ return constraint ;
788
+ } ;
779
789
self . constraints = [ ] ;
780
790
var includeExcludeDefined = metadata . constraints . excludePath || metadata . constraints . includePath ;
781
791
// Support existing configuration style.
@@ -830,18 +840,8 @@ function orEmptyArray(v) {
830
840
}
831
841
}
832
842
833
- self . constraints . value = function ( constraint ) {
834
- if ( _ . isObject ( constraint ) ) {
835
- return constraint [ valueProperty ] ;
836
- }
837
- return constraint ;
838
- } ;
839
- self . constraints . text = function ( constraint ) {
840
- if ( _ . isObject ( constraint ) ) {
841
- return constraint [ textProperty ] ;
842
- }
843
- return constraint ;
844
- } ;
843
+ self . constraints . value = self . constraintValue ;
844
+ self . constraints . text = self . constraintText ;
845
845
self . constraints . label = function ( value ) {
846
846
847
847
if ( ! value && ko . isObservable ( self ) ) {
@@ -1267,6 +1267,24 @@ function orEmptyArray(v) {
1267
1267
self . iterateOverPath ( pathAsArray , callback , self . data ) ;
1268
1268
}
1269
1269
1270
+ /**
1271
+ * Iterates over every instance of the DataModelItem defined by path and returns an array containing
1272
+ * the values found at each item.
1273
+ * @param path the path to the data model item of interest (e.g. list.nestedList.textValue1)
1274
+ * @returns {*[] }
1275
+ */
1276
+ self . getModelValuesForPath = function ( path ) {
1277
+ var values = [ ] ;
1278
+ self . eachValueForPath ( path , function ( val ) {
1279
+ if ( _ . isArray ( val ) ) {
1280
+ values = values . concat ( val ) ;
1281
+ } else if ( val != null ) {
1282
+ values . push ( val ) ;
1283
+ }
1284
+ } ) ;
1285
+ return values ;
1286
+ }
1287
+
1270
1288
/**
1271
1289
* Recursively iterates over each element in the supplied pathAsArray, taking into
1272
1290
* account when values are lists.
0 commit comments