@@ -1022,6 +1022,171 @@ describe('MatDialog', () => {
1022
1022
) ;
1023
1023
} ) ;
1024
1024
1025
+ describe ( 'closePredicate option' , ( ) => {
1026
+ function getDialogs ( ) {
1027
+ return overlayContainerElement . querySelectorAll ( 'mat-dialog-container' ) ;
1028
+ }
1029
+
1030
+ it ( 'should determine whether closing via the backdrop is allowed' , fakeAsync ( ( ) => {
1031
+ let canClose = false ;
1032
+ const closedSpy = jasmine . createSpy ( 'closed spy' ) ;
1033
+ const ref = dialog . open ( PizzaMsg , {
1034
+ closePredicate : ( ) => canClose ,
1035
+ viewContainerRef : testViewContainerRef ,
1036
+ } ) ;
1037
+
1038
+ ref . afterClosed ( ) . subscribe ( closedSpy ) ;
1039
+ viewContainerFixture . detectChanges ( ) ;
1040
+
1041
+ expect ( getDialogs ( ) . length ) . toBe ( 1 ) ;
1042
+
1043
+ let backdrop = overlayContainerElement . querySelector ( '.cdk-overlay-backdrop' ) as HTMLElement ;
1044
+ backdrop . click ( ) ;
1045
+ viewContainerFixture . detectChanges ( ) ;
1046
+ flush ( ) ;
1047
+
1048
+ expect ( getDialogs ( ) . length ) . toBe ( 1 ) ;
1049
+ expect ( closedSpy ) . not . toHaveBeenCalled ( ) ;
1050
+
1051
+ canClose = true ;
1052
+ backdrop . click ( ) ;
1053
+ viewContainerFixture . detectChanges ( ) ;
1054
+ flush ( ) ;
1055
+
1056
+ expect ( getDialogs ( ) . length ) . toBe ( 0 ) ;
1057
+ expect ( closedSpy ) . toHaveBeenCalledTimes ( 1 ) ;
1058
+ } ) ) ;
1059
+
1060
+ it ( 'should determine whether closing via the escape key is allowed' , fakeAsync ( ( ) => {
1061
+ let canClose = false ;
1062
+ const closedSpy = jasmine . createSpy ( 'closed spy' ) ;
1063
+ const ref = dialog . open ( PizzaMsg , {
1064
+ closePredicate : ( ) => canClose ,
1065
+ viewContainerRef : testViewContainerRef ,
1066
+ } ) ;
1067
+
1068
+ ref . afterClosed ( ) . subscribe ( closedSpy ) ;
1069
+ viewContainerFixture . detectChanges ( ) ;
1070
+
1071
+ expect ( getDialogs ( ) . length ) . toBe ( 1 ) ;
1072
+
1073
+ dispatchKeyboardEvent ( document . body , 'keydown' , ESCAPE ) ;
1074
+ viewContainerFixture . detectChanges ( ) ;
1075
+ flush ( ) ;
1076
+
1077
+ expect ( getDialogs ( ) . length ) . toBe ( 1 ) ;
1078
+ expect ( closedSpy ) . not . toHaveBeenCalled ( ) ;
1079
+
1080
+ canClose = true ;
1081
+ dispatchKeyboardEvent ( document . body , 'keydown' , ESCAPE ) ;
1082
+ viewContainerFixture . detectChanges ( ) ;
1083
+ flush ( ) ;
1084
+
1085
+ expect ( getDialogs ( ) . length ) . toBe ( 0 ) ;
1086
+ expect ( closedSpy ) . toHaveBeenCalledTimes ( 1 ) ;
1087
+ } ) ) ;
1088
+
1089
+ it ( 'should determine whether closing via the `close` method is allowed' , fakeAsync ( ( ) => {
1090
+ let canClose = false ;
1091
+ const closedSpy = jasmine . createSpy ( 'closed spy' ) ;
1092
+ const ref = dialog . open ( PizzaMsg , {
1093
+ closePredicate : ( ) => canClose ,
1094
+ viewContainerRef : testViewContainerRef ,
1095
+ } ) ;
1096
+
1097
+ ref . afterClosed ( ) . subscribe ( closedSpy ) ;
1098
+ viewContainerFixture . detectChanges ( ) ;
1099
+
1100
+ expect ( getDialogs ( ) . length ) . toBe ( 1 ) ;
1101
+
1102
+ ref . close ( ) ;
1103
+ viewContainerFixture . detectChanges ( ) ;
1104
+ flush ( ) ;
1105
+
1106
+ expect ( getDialogs ( ) . length ) . toBe ( 1 ) ;
1107
+ expect ( closedSpy ) . not . toHaveBeenCalled ( ) ;
1108
+
1109
+ canClose = true ;
1110
+ ref . close ( 'hello' ) ;
1111
+ viewContainerFixture . detectChanges ( ) ;
1112
+ flush ( ) ;
1113
+
1114
+ expect ( getDialogs ( ) . length ) . toBe ( 0 ) ;
1115
+ expect ( closedSpy ) . toHaveBeenCalledTimes ( 1 ) ;
1116
+ expect ( closedSpy ) . toHaveBeenCalledWith ( 'hello' ) ;
1117
+ } ) ) ;
1118
+
1119
+ it ( 'should not be closed by `closeAll` if not allowed by the predicate' , fakeAsync ( ( ) => {
1120
+ let canClose = false ;
1121
+ const config = { closePredicate : ( ) => canClose } ;
1122
+ const spy = jasmine . createSpy ( 'afterAllClosed spy' ) ;
1123
+ dialog . open ( PizzaMsg , config ) ;
1124
+ viewContainerFixture . detectChanges ( ) ;
1125
+ dialog . open ( PizzaMsg , config ) ;
1126
+ viewContainerFixture . detectChanges ( ) ;
1127
+ dialog . open ( PizzaMsg , config ) ;
1128
+ viewContainerFixture . detectChanges ( ) ;
1129
+
1130
+ const subscription = dialog . afterAllClosed . subscribe ( spy ) ;
1131
+ expect ( getDialogs ( ) . length ) . toBe ( 3 ) ;
1132
+ expect ( dialog . openDialogs . length ) . toBe ( 3 ) ;
1133
+
1134
+ dialog . closeAll ( ) ;
1135
+ viewContainerFixture . detectChanges ( ) ;
1136
+ flush ( ) ;
1137
+
1138
+ expect ( getDialogs ( ) . length ) . toBe ( 3 ) ;
1139
+ expect ( dialog . openDialogs . length ) . toBe ( 3 ) ;
1140
+ expect ( spy ) . not . toHaveBeenCalled ( ) ;
1141
+
1142
+ canClose = true ;
1143
+ dialog . closeAll ( ) ;
1144
+ viewContainerFixture . detectChanges ( ) ;
1145
+ flush ( ) ;
1146
+
1147
+ expect ( getDialogs ( ) . length ) . toBe ( 0 ) ;
1148
+ expect ( dialog . openDialogs . length ) . toBe ( 0 ) ;
1149
+ expect ( spy ) . toHaveBeenCalledTimes ( 1 ) ;
1150
+
1151
+ subscription . unsubscribe ( ) ;
1152
+ } ) ) ;
1153
+
1154
+ it ( 'should recapture focus to the first tabbable element when clicking on the backdrop while the `closePredicate` is blocking the close sequence' , fakeAsync ( ( ) => {
1155
+ // When testing focus, all of the elements must be in the DOM.
1156
+ document . body . appendChild ( overlayContainerElement ) ;
1157
+
1158
+ dialog . open ( PizzaMsg , {
1159
+ closePredicate : ( ) => false ,
1160
+ viewContainerRef : testViewContainerRef ,
1161
+ } ) ;
1162
+
1163
+ viewContainerFixture . detectChanges ( ) ;
1164
+ flush ( ) ;
1165
+ viewContainerFixture . detectChanges ( ) ;
1166
+ flush ( ) ;
1167
+
1168
+ const backdrop = overlayContainerElement . querySelector (
1169
+ '.cdk-overlay-backdrop' ,
1170
+ ) as HTMLElement ;
1171
+ const input = overlayContainerElement . querySelector ( 'input' ) as HTMLInputElement ;
1172
+
1173
+ expect ( document . activeElement )
1174
+ . withContext ( 'Expected input to be focused on open' )
1175
+ . toBe ( input ) ;
1176
+
1177
+ input . blur ( ) ; // Programmatic clicks might not move focus so we simulate it.
1178
+ backdrop . click ( ) ;
1179
+ viewContainerFixture . detectChanges ( ) ;
1180
+ flush ( ) ;
1181
+
1182
+ expect ( document . activeElement )
1183
+ . withContext ( 'Expected input to stay focused after click' )
1184
+ . toBe ( input ) ;
1185
+
1186
+ overlayContainerElement . remove ( ) ;
1187
+ } ) ) ;
1188
+ } ) ;
1189
+
1025
1190
it (
1026
1191
'should recapture focus to the first header when clicking on the backdrop with ' +
1027
1192
'autoFocus set to "first-heading"' ,
0 commit comments