max*_*oin 17 jquery twitter-bootstrap angularjs angular-ui-bootstrap angularjs-ng-click
Twitter Bootstrap dropdown嵌套在一个tr.在tr通过可点击ng-click.单击页面上的任意位置将折叠下拉菜单.该行为在指令中定义$document.bind('click', closeMenu).
因此,当菜单打开,并且用户单击一行时,我希望菜单关闭(就像它一样)并且我想阻止该行上的click事件.
JSFiddle:http://jsfiddle.net/LMc2f/1/
JSFiddle +指令内联:http://jsfiddle.net/9DM8U/1/
来自ui-bootstrap-tpls-0.10.0.js的相关代码:
angular.module('ui.bootstrap.dropdownToggle', []).directive('dropdownToggle', ['$document', '$location', function ($document, $location) {
var openElement = null,
closeMenu = angular.noop;
return {
restrict: 'CA',
link: function(scope, element, attrs) {
scope.$watch('$location.path', function() { closeMenu(); });
element.parent().bind('click', function() { closeMenu(); });
element.bind('click', function (event) {
var elementWasOpen = (element === openElement);
event.preventDefault();
event.stopPropagation();
if (!!openElement) {
closeMenu();
}
if (!elementWasOpen && !element.hasClass('disabled') && !element.prop('disabled')) {
element.parent().addClass('open');
openElement = element;
closeMenu = function (event) {
if (event) {
event.preventDefault();
event.stopPropagation();
}
$document.unbind('click', closeMenu);
element.parent().removeClass('open');
closeMenu = angular.noop;
openElement = null;
};
$document.bind('click', closeMenu);
}
});
}
};
}]);
Run Code Online (Sandbox Code Playgroud)
我无法弄清楚如何阻止ng-click内部的基础事件closeMenu.
注意:我找不到访问方式,$event所以我无法尝试$event.stopPropagation().
小智 20
我倾向于$event.stopPropagation()从模板本身内调用.与事件相关的逻辑很可能属于那里.应该使单元测试更容易.看模板的人也会知道事件在没有查看底层控制器的情况下没有冒泡.
<div ng-click="parentHandler()">
<div ng-click="childHandler(); $event.stopPropagation()"></div>
</div>
Run Code Online (Sandbox Code Playgroud)
Ste*_*wie 16
dropdown指令绑定文档上的click事件,但是当您单击该行时,事件开始从目标元素向下传播到根文档节点(td- > tr- > table- > document).
这就是为什么ng-click即使指令在文档点击时"停止"气泡,你的行上的处理程序也会被调用.
解决方案是在添加文档的单击处理程序时使用useCapture标志.
启动捕获后,指定类型的所有事件将被分派到已注册的侦听器,然后再分派到DOM树中它下面的任何EventTarget.MDN
现在,要指示dropdown指令使用您自己的处理程序,您需要更改指令的源.但这是第三方指令,出于维护原因,您可能不希望这样做.
这是强大的角度$装饰器开始的地方.您可以使用$ decorator动态更改第三方模块的源,而不实际触及实际的源文件.
因此,使用装饰器,并在文档节点上使用自定义事件处理程序,这就是您可以使该下拉列表的行为:
var myApp = angular.module('myApp', []);
/**
* Original dropdownToggle directive from ui-bootstrap.
* Nothing changed here.
*/
myApp.directive('dropdownToggle', ['$document', '$location', function ($document, $location) {
var openElement = null,
closeMenu = angular.noop;
return {
restrict: 'CA',
link: function(scope, element, attrs) {
scope.$watch('$location.path', function() { closeMenu(); });
element.parent().bind('click', function() { closeMenu(); });
element.bind('click', function (event) {
var elementWasOpen = (element === openElement);
event.preventDefault();
event.stopPropagation();
if (!!openElement) {
closeMenu();
}
if (!elementWasOpen && !element.hasClass('disabled') && !element.prop('disabled')) {
element.parent().addClass('open');
openElement = element;
closeMenu = function (event) {
if (event) {
event.preventDefault();
event.stopPropagation();
}
$document.unbind('click', closeMenu);
element.parent().removeClass('open');
closeMenu = angular.noop;
openElement = null;
};
$document.bind('click', closeMenu); /* <--- CAUSE OF ALL PROBLEMS ----- */
}
});
}
};
}]);
/**
* This is were we decorate the dropdownToggle directive
* in order to change the way the document click handler works
*/
myApp.config(function($provide){
'use strict';
$provide.decorator('dropdownToggleDirective', [
'$delegate',
'$document',
function ($delegate, $document) {
var directive = $delegate[0];
var openElement = null;
var closeMenu = angular.noop;
function handler(e){
var elm = angular.element(e.target);
if(!elm.parents('.dropdown-menu').length){
e.stopPropagation();
e.preventDefault();
}
closeMenu();
// After closing the menu, we remove the all-seeing handler
// to allow the application click events to work nnormally
$document[0].removeEventListener('click', handler, true);
}
directive.compile = function(){
return function(scope, element) {
scope.$watch('$location.path', closeMenu);
element.parent().bind('click', closeMenu);
element.bind('click', function (event) {
var elementWasOpen = (element === openElement);
event.preventDefault();
event.stopPropagation();
if (!!openElement) {
closeMenu();
}
if (!elementWasOpen && !element.hasClass('disabled') && !element.prop('disabled')) {
element.parent().addClass('open');
openElement = element;
closeMenu = function (event) {
if (event) {
event.preventDefault();
event.stopPropagation();
}
$document.unbind('click', closeMenu);
element.parent().removeClass('open');
closeMenu = angular.noop;
openElement = null;
};
// We attach the click handler by specifying the third "useCapture" parameter as true
$document[0].addEventListener('click', handler, true);
}
});
};
};
return $delegate;
}
]);
});
Run Code Online (Sandbox Code Playgroud)
更新:
请注意,更新的自定义处理程序将阻止冒泡,除非目标元素是实际的下拉选项.这将解决即使单击下拉选项时阻止单击事件的问题.
这仍然不会阻止事件向下冒泡到行(从下拉选项),但这与下拉指令没有任何关系.无论如何,为了防止这种冒泡,你可以将$event对象传递给ng-click表达式函数,并使用该对象来阻止even向下冒泡到表行:
<div ng-controller="DropdownCtrl">
<table>
<tr ng-click="clicked('row')">
<td>
<div class="btn-group">
<button type="button" class="btn btn-default dropdown-toggle">
Action <span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu">
<li ng-repeat="choice in items">
<a ng-click="clicked('link element', $event)">{{choice}}</a>
</li>
</ul>
</div>
</td>
</tr>
</table>
</div>
Run Code Online (Sandbox Code Playgroud)
function DropdownCtrl($scope) {
$scope.items = [
"Action",
"Another action",
"Something else here"
];
$scope.clicked = function(what, event) {
alert(what + ' clicked');
if(event){
event.stopPropagation();
event.preventDefault();
}
}
}
Run Code Online (Sandbox Code Playgroud)
koo*_*nix 12
你需要在小提琴的第2行传递ng-click的事件,然后在你的方法中对该对象进行preventDefault和stopPropigation
<tr ng-click="do($event)">
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
44163 次 |
| 最近记录: |