Skip to content

Commit 8802a0d

Browse files
committed
Merge pull request #966 from romario333/sref-preventdefault
fix(uiSref): cancel transition if preventDefault() has been called
2 parents 54004a1 + 2e6d916 commit 8802a0d

File tree

2 files changed

+41
-7
lines changed

2 files changed

+41
-7
lines changed

Diff for: src/stateDirectives.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -128,10 +128,14 @@ function $StateRefDirective($state, $timeout) {
128128
var button = e.which || e.button;
129129
if ( !(button > 1 || e.ctrlKey || e.metaKey || e.shiftKey || element.attr('target')) ) {
130130
// HACK: This is to allow ng-clicks to be processed before the transition is initiated:
131-
$timeout(function() {
131+
var transition = $timeout(function() {
132132
$state.go(ref.state, params, options);
133133
});
134134
e.preventDefault();
135+
136+
e.preventDefault = function() {
137+
$timeout.cancel(transition);
138+
};
135139
}
136140
});
137141
}

Diff for: test/stateDirectivesSpec.js

+36-6
Original file line numberDiff line numberDiff line change
@@ -75,15 +75,25 @@ describe('uiStateRef', function() {
7575
});
7676

7777
describe('links', function() {
78+
var timeoutFlush;
7879

79-
beforeEach(inject(function($rootScope, $compile) {
80+
beforeEach(inject(function($rootScope, $compile, $timeout) {
8081
el = angular.element('<a ui-sref="contacts.item.detail({ id: contact.id })">Details</a>');
8182
scope = $rootScope;
8283
scope.contact = { id: 5 };
8384
scope.$apply();
8485

8586
$compile(el)(scope);
8687
scope.$digest();
88+
89+
timeoutFlush = function() {
90+
try {
91+
$timeout.flush();
92+
} catch (e) {
93+
// Angular 1.0.8 throws 'No deferred tasks to be flushed' if there is nothing in queue.
94+
// Behave as Angular >=1.1.5 and do nothing in such case.
95+
}
96+
}
8797
}));
8898

8999
it('should generate the correct href', function() {
@@ -107,18 +117,18 @@ describe('uiStateRef', function() {
107117
expect(el.attr('href')).toBe('#/contacts/3');
108118
}));
109119

110-
it('should transition states when left-clicked', inject(function($state, $stateParams, $document, $q, $timeout) {
120+
it('should transition states when left-clicked', inject(function($state, $stateParams, $document, $q) {
111121
expect($state.$current.name).toEqual('');
112122

113123
triggerClick(el);
114-
$timeout.flush();
124+
timeoutFlush();
115125
$q.flush();
116126

117127
expect($state.current.name).toEqual('contacts.item.detail');
118128
expect($stateParams).toEqual({ id: "5" });
119129
}));
120130

121-
it('should transition when given a click that contains no data (fake-click)', inject(function($state, $stateParams, $document, $q, $timeout) {
131+
it('should transition when given a click that contains no data (fake-click)', inject(function($state, $stateParams, $document, $q) {
122132
expect($state.current.name).toEqual('');
123133

124134
triggerClick(el, {
@@ -128,7 +138,7 @@ describe('uiStateRef', function() {
128138
altKey: undefined,
129139
button: undefined
130140
});
131-
$timeout.flush();
141+
timeoutFlush();
132142
$q.flush();
133143

134144
expect($state.current.name).toEqual('contacts.item.detail');
@@ -139,7 +149,9 @@ describe('uiStateRef', function() {
139149
expect($state.$current.name).toEqual('');
140150
triggerClick(el, { ctrlKey: true });
141151

152+
timeoutFlush();
142153
$q.flush();
154+
143155
expect($state.current.name).toEqual('');
144156
expect($stateParams).toEqual({ id: "5" });
145157
}));
@@ -148,6 +160,7 @@ describe('uiStateRef', function() {
148160
expect($state.$current.name).toEqual('');
149161

150162
triggerClick(el, { metaKey: true });
163+
timeoutFlush();
151164
$q.flush();
152165

153166
expect($state.current.name).toEqual('');
@@ -158,6 +171,7 @@ describe('uiStateRef', function() {
158171
expect($state.$current.name).toEqual('');
159172

160173
triggerClick(el, { shiftKey: true });
174+
timeoutFlush();
161175
$q.flush();
162176

163177
expect($state.current.name).toEqual('');
@@ -168,17 +182,33 @@ describe('uiStateRef', function() {
168182
expect($state.$current.name).toEqual('');
169183

170184
triggerClick(el, { button: 1 });
185+
timeoutFlush();
171186
$q.flush();
172187

173188
expect($state.current.name).toEqual('');
174189
expect($stateParams).toEqual({ id: "5" });
175190
}));
176191

177-
it('should not transition states when element has target specified', inject(function($state, $stateParams, $document, $q, $timeout) {
192+
it('should not transition states when element has target specified', inject(function($state, $stateParams, $document, $q) {
178193
el.attr('target', '_blank');
179194
expect($state.$current.name).toEqual('');
180195

181196
triggerClick(el);
197+
timeoutFlush();
198+
$q.flush();
199+
200+
expect($state.current.name).toEqual('');
201+
expect($stateParams).toEqual({ id: "5" });
202+
}));
203+
204+
it('should not transition states if preventDefault() is called in click handler', inject(function($state, $stateParams, $document, $q) {
205+
expect($state.$current.name).toEqual('');
206+
el.bind('click', function(e) {
207+
e.preventDefault();
208+
});
209+
210+
triggerClick(el);
211+
timeoutFlush();
182212
$q.flush();
183213

184214
expect($state.current.name).toEqual('');

0 commit comments

Comments
 (0)