Skip to content

Commit 8248e77

Browse files
IgorMinarmhevery
authored andcommitted
'A' tag widget and ng:click propagation change
* added a widget for A (anchor) tag, that modifies the default behavior and prevent default action (location change and page reload) for tags with empty href attribute * stopped event propagation for all ng:click handlers
1 parent 0af763d commit 8248e77

4 files changed

Lines changed: 80 additions & 1 deletion

File tree

src/directives.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,13 +198,22 @@ angularWidget("@ng:repeat", function(expression, element){
198198
};
199199
});
200200

201+
202+
/*
203+
* A directive that allows creation of custom onclick handlers that are defined as angular
204+
* expressions and are compiled and executed within the current scope.
205+
*
206+
* Events that are handled via these handler are always configured not to propagate further.
207+
*
208+
* TODO: maybe we should consider allowing users to control even propagation in the future.
209+
*/
201210
angularDirective("ng:click", function(expression, element){
202211
return function(element){
203212
var self = this;
204213
element.bind('click', function(event){
205214
self.$tryEval(expression, element);
206215
self.$root.$eval();
207-
event.preventDefault();
216+
event.stopPropagation();
208217
});
209218
};
210219
});

src/widgets.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,3 +340,25 @@ var ngSwitch = angularWidget('ng:switch', function (element){
340340
},
341341
route: switchRouteMatcher
342342
});
343+
344+
345+
/*
346+
* Modifies the default behavior of html A tag, so that the default action is prevented when href
347+
* attribute is empty.
348+
*
349+
* The reasoning for this change is to allow easy creation of action links with ng:click without
350+
* changing the location or causing page reloads, e.g.:
351+
* <a href="" ng:click="model.$save()">Save</a>
352+
*/
353+
angular.widget('a', function() {
354+
this.descend(true);
355+
this.directives(true);
356+
357+
return function(element) {
358+
if (element.attr('href') === '') {
359+
element.bind('click', function(event){
360+
event.preventDefault();
361+
});
362+
}
363+
};
364+
});

test/directivesSpec.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,19 @@ describe("directives", function(){
169169
element.trigger('click');
170170
expect(scope.$get('clicked')).toEqual(true);
171171
});
172+
173+
it('should stop event propagation', function() {
174+
var scope = compile('<div ng:click="outer = true"><div ng:click="inner = true"></div></div>');
175+
scope.$eval();
176+
expect(scope.$get('outer')).not.toBeDefined();
177+
expect(scope.$get('inner')).not.toBeDefined();
178+
179+
var innerDiv = jqLite(element.children()[0]);
180+
181+
innerDiv.trigger('click');
182+
expect(scope.$get('outer')).not.toBeDefined();
183+
expect(scope.$get('inner')).toEqual(true);
184+
})
172185
});
173186

174187
it('should ng:class', function(){

test/widgetsSpec.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,5 +498,40 @@ describe("widget", function(){
498498
expect(element.text()).toEqual('');
499499
});
500500
});
501+
502+
describe('a', function() {
503+
it('should prevent default action to be executed when href is empty', function() {
504+
var orgLocation = document.location.href,
505+
preventDefaultCalled = false,
506+
event;
507+
508+
compile('<a href="">empty link</a>');
509+
510+
if (msie) {
511+
512+
event = document.createEventObject();
513+
expect(event.returnValue).not.toBeDefined();
514+
element[0].fireEvent('onclick', event);
515+
expect(event.returnValue).toEqual(false);
516+
517+
} else {
518+
519+
event = document.createEvent('MouseEvent');
520+
event.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, _null);
521+
522+
event.preventDefaultOrg = event.preventDefault;
523+
event.preventDefault = function() {
524+
preventDefaultCalled = true;
525+
if (this.preventDefaultOrg) this.preventDefaultOrg();
526+
};
527+
528+
element[0].dispatchEvent(event);
529+
530+
expect(preventDefaultCalled).toEqual(true);
531+
}
532+
533+
expect(document.location.href).toEqual(orgLocation);
534+
});
535+
})
501536
});
502537

0 commit comments

Comments
 (0)