aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIgor Minar2010-09-30 23:07:36 +0800
committerMisko Hevery2010-10-01 07:44:46 +0800
commit8248e77a7b910bcbc71ca25c06bef44dd6712990 (patch)
tree333b5b91e914a96f27b214bac3ef61c8d04e5b4d
parent0af763dcec8b9f6b17208ac58607cd1124382f63 (diff)
downloadangular.js-8248e77a7b910bcbc71ca25c06bef44dd6712990.tar.bz2
'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
-rw-r--r--src/directives.js11
-rw-r--r--src/widgets.js22
-rw-r--r--test/directivesSpec.js13
-rw-r--r--test/widgetsSpec.js35
4 files changed, 80 insertions, 1 deletions
diff --git a/src/directives.js b/src/directives.js
index 69648e31..4443cc9d 100644
--- a/src/directives.js
+++ b/src/directives.js
@@ -198,13 +198,22 @@ angularWidget("@ng:repeat", function(expression, element){
};
});
+
+/*
+ * A directive that allows creation of custom onclick handlers that are defined as angular
+ * expressions and are compiled and executed within the current scope.
+ *
+ * Events that are handled via these handler are always configured not to propagate further.
+ *
+ * TODO: maybe we should consider allowing users to control even propagation in the future.
+ */
angularDirective("ng:click", function(expression, element){
return function(element){
var self = this;
element.bind('click', function(event){
self.$tryEval(expression, element);
self.$root.$eval();
- event.preventDefault();
+ event.stopPropagation();
});
};
});
diff --git a/src/widgets.js b/src/widgets.js
index fbca8436..24eba900 100644
--- a/src/widgets.js
+++ b/src/widgets.js
@@ -340,3 +340,25 @@ var ngSwitch = angularWidget('ng:switch', function (element){
},
route: switchRouteMatcher
});
+
+
+/*
+ * Modifies the default behavior of html A tag, so that the default action is prevented when href
+ * attribute is empty.
+ *
+ * The reasoning for this change is to allow easy creation of action links with ng:click without
+ * changing the location or causing page reloads, e.g.:
+ * <a href="" ng:click="model.$save()">Save</a>
+ */
+angular.widget('a', function() {
+ this.descend(true);
+ this.directives(true);
+
+ return function(element) {
+ if (element.attr('href') === '') {
+ element.bind('click', function(event){
+ event.preventDefault();
+ });
+ }
+ };
+}); \ No newline at end of file
diff --git a/test/directivesSpec.js b/test/directivesSpec.js
index f0eb5c09..72f7b2f2 100644
--- a/test/directivesSpec.js
+++ b/test/directivesSpec.js
@@ -169,6 +169,19 @@ describe("directives", function(){
element.trigger('click');
expect(scope.$get('clicked')).toEqual(true);
});
+
+ it('should stop event propagation', function() {
+ var scope = compile('<div ng:click="outer = true"><div ng:click="inner = true"></div></div>');
+ scope.$eval();
+ expect(scope.$get('outer')).not.toBeDefined();
+ expect(scope.$get('inner')).not.toBeDefined();
+
+ var innerDiv = jqLite(element.children()[0]);
+
+ innerDiv.trigger('click');
+ expect(scope.$get('outer')).not.toBeDefined();
+ expect(scope.$get('inner')).toEqual(true);
+ })
});
it('should ng:class', function(){
diff --git a/test/widgetsSpec.js b/test/widgetsSpec.js
index d113e6ee..edaa5061 100644
--- a/test/widgetsSpec.js
+++ b/test/widgetsSpec.js
@@ -498,5 +498,40 @@ describe("widget", function(){
expect(element.text()).toEqual('');
});
});
+
+ describe('a', function() {
+ it('should prevent default action to be executed when href is empty', function() {
+ var orgLocation = document.location.href,
+ preventDefaultCalled = false,
+ event;
+
+ compile('<a href="">empty link</a>');
+
+ if (msie) {
+
+ event = document.createEventObject();
+ expect(event.returnValue).not.toBeDefined();
+ element[0].fireEvent('onclick', event);
+ expect(event.returnValue).toEqual(false);
+
+ } else {
+
+ event = document.createEvent('MouseEvent');
+ event.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, _null);
+
+ event.preventDefaultOrg = event.preventDefault;
+ event.preventDefault = function() {
+ preventDefaultCalled = true;
+ if (this.preventDefaultOrg) this.preventDefaultOrg();
+ };
+
+ element[0].dispatchEvent(event);
+
+ expect(preventDefaultCalled).toEqual(true);
+ }
+
+ expect(document.location.href).toEqual(orgLocation);
+ });
+ })
});