'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
This commit is contained in:
Igor Minar 2010-09-30 23:07:36 +08:00 committed by Misko Hevery
parent 0af763dcec
commit 8248e77a7b
4 changed files with 80 additions and 1 deletions

View file

@ -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();
});
};
});

View file

@ -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();
});
}
};
});

View file

@ -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(){

View file

@ -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);
});
})
});