@@ -129,14 +129,28 @@ describe('form', function() {
129
129
130
130
it ( 'should prevent form submission' , function ( ) {
131
131
var nextTurn = false ,
132
+ submitted = false ,
132
133
reloadPrevented ;
133
134
134
- doc = jqLite ( '<form><input type="submit" value="submit" ></form>' ) ;
135
+ doc = jqLite ( '<form ng-submit="submitMe()">' +
136
+ '<input type="submit" value="submit">' +
137
+ '</form>' ) ;
138
+
139
+ var assertPreventDefaultListener = function ( e ) {
140
+ reloadPrevented = e . defaultPrevented || ( e . returnValue === false ) ;
141
+ } ;
142
+
143
+ // native dom event listeners in IE8 fire in LIFO order so we have to register them
144
+ // there in different order than in other browsers
145
+ if ( msie == 8 ) addEventListenerFn ( doc [ 0 ] , 'submit' , assertPreventDefaultListener ) ;
146
+
135
147
$compile ( doc ) ( scope ) ;
136
148
137
- doc . bind ( 'submit' , function ( e ) {
138
- reloadPrevented = e . defaultPrevented ;
139
- } ) ;
149
+ scope . submitMe = function ( ) {
150
+ submitted = true ;
151
+ }
152
+
153
+ if ( msie != 8 ) addEventListenerFn ( doc [ 0 ] , 'submit' , assertPreventDefaultListener ) ;
140
154
141
155
browserTrigger ( doc . find ( 'input' ) ) ;
142
156
@@ -147,17 +161,92 @@ describe('form', function() {
147
161
148
162
runs ( function ( ) {
149
163
expect ( reloadPrevented ) . toBe ( true ) ;
164
+ expect ( submitted ) . toBe ( true ) ;
165
+
166
+ // prevent mem leak in test
167
+ removeEventListenerFn ( doc [ 0 ] , 'submit' , assertPreventDefaultListener ) ;
150
168
} ) ;
151
169
} ) ;
152
170
153
171
154
- it ( 'should not prevent form submission if action attribute present' , function ( ) {
172
+ it ( 'should prevent the default when the form is destroyed by a submission via a click event' ,
173
+ inject ( function ( $timeout ) {
174
+ doc = jqLite ( '<div>' +
175
+ '<form ng-submit="submitMe()">' +
176
+ '<button ng-click="destroy()"></button>' +
177
+ '</form>' +
178
+ '</div>' ) ;
179
+
180
+ var form = doc . find ( 'form' ) ,
181
+ destroyed = false ,
182
+ nextTurn = false ,
183
+ submitted = false ,
184
+ reloadPrevented ;
185
+
186
+ scope . destroy = function ( ) {
187
+ // yes, I know, scope methods should not do direct DOM manipulation, but I wanted to keep
188
+ // this test small. Imagine that the destroy action will cause a model change (e.g.
189
+ // $location change) that will cause some directive to destroy the dom (e.g. ngView+$route)
190
+ doc . html ( '' ) ;
191
+ destroyed = true ;
192
+ }
193
+
194
+ scope . submitMe = function ( ) {
195
+ submitted = true ;
196
+ }
197
+
198
+ var assertPreventDefaultListener = function ( e ) {
199
+ reloadPrevented = e . defaultPrevented || ( e . returnValue === false ) ;
200
+ } ;
201
+
202
+ // native dom event listeners in IE8 fire in LIFO order so we have to register them
203
+ // there in different order than in other browsers
204
+ if ( msie == 8 ) addEventListenerFn ( form [ 0 ] , 'submit' , assertPreventDefaultListener ) ;
205
+
206
+ $compile ( doc ) ( scope ) ;
207
+
208
+ if ( msie != 8 ) addEventListenerFn ( form [ 0 ] , 'submit' , assertPreventDefaultListener ) ;
209
+
210
+ browserTrigger ( doc . find ( 'button' ) , 'click' ) ;
211
+
212
+ // let the browser process all events (and potentially reload the page)
213
+ setTimeout ( function ( ) { nextTurn = true ; } , 100 ) ;
214
+
215
+ waitsFor ( function ( ) { return nextTurn ; } ) ;
216
+
217
+
218
+ // I can't get IE8 to automatically trigger submit in this test, in production it does it
219
+ // properly
220
+ if ( msie == 8 ) browserTrigger ( form , 'submit' ) ;
221
+
222
+ runs ( function ( ) {
223
+ expect ( doc . html ( ) ) . toBe ( '' ) ;
224
+ expect ( destroyed ) . toBe ( true ) ;
225
+ expect ( submitted ) . toBe ( false ) ; // this is known corner-case that is not currently handled
226
+ // the issue is that the submit listener is destroyed before
227
+ // the event propagates there. we can fix this if we see
228
+ // the issue in the wild, I'm not going to bother to do it
229
+ // now. (i)
230
+
231
+ // IE9 is special and it doesn't fire submit event when form was destroyed
232
+ if ( msie != 9 ) {
233
+ expect ( reloadPrevented ) . toBe ( true ) ;
234
+ $timeout . flush ( ) ;
235
+ }
236
+
237
+ // prevent mem leak in test
238
+ removeEventListenerFn ( form [ 0 ] , 'submit' , assertPreventDefaultListener ) ;
239
+ } ) ;
240
+ } ) ) ;
241
+
242
+
243
+ it ( 'should NOT prevent form submission if action attribute present' , function ( ) {
155
244
var callback = jasmine . createSpy ( 'submit' ) . andCallFake ( function ( event ) {
156
245
expect ( event . isDefaultPrevented ( ) ) . toBe ( false ) ;
157
246
event . preventDefault ( ) ;
158
247
} ) ;
159
248
160
- doc = $compile ( '<form name="x" action="some.py" / >' ) ( scope ) ;
249
+ doc = $compile ( '<form action="some.py"></form >' ) ( scope ) ;
161
250
doc . bind ( 'submit' , callback ) ;
162
251
163
252
browserTrigger ( doc , 'submit' ) ;
0 commit comments