我们的Web应用程序当前具有可折叠的侧边菜单,其逻辑通过称为CleanZone的外部库进行处理。 加载子菜单项时出现问题。当菜单折叠时,这些内容会在页面加载后添加到DOM中,从而导致click事件处理程序(通过ng-click传递)不响应。
通常对于这样的事情,我们将创建一个指令,然后通过$ compile服务将其附加到DOM。但是,在这种情况下,我需要依赖此外部库的逻辑,该库本身不使用AngularJS。
是否有可能以某种方式捕获此库添加到HTML中的所有内容,并通过AngularJS重新编译它,以便ng-click事件对其起作用?
以下代码可帮助您理解问题:
DOM始终包含以下内容:
<ul class="sub-menu">
<li>
<a ng-click="someFunction()" href="#">Text</a>
</li>
</ul>
如果菜单未折叠,则会显示上面的子菜单,因为它已经在DOM中,所以ng-click才起作用。
但是,当折叠菜单时,用户必须将鼠标悬停在菜单上的图标上,然后动态添加子菜单:
<div id="sub-menu-nav">
<ul class="sub-menu">
<li>
<a ng-click="someFunction()" href="#"></a>
</li>
</ul>
</div>
这是该库添加元素的相关部分:
/*SubMenu hover */
var tool = $("<div id='sub-menu-nav' style='position:fixed;z-index:9999;'></div>");
function showMenu(_this, e) {
if (($("#cl-wrapper").hasClass("sb-collapsed")) {
var menu = $("ul", _this);
tool.appendTo("body");
tool.html('<ul class="sub-menu">' + menu.html() + '</ul>');
tool.show();
} else {
tool.hide();
}
}
$(".cl-vnavigation li").hover(function (e) {
showMenu(this, e);
}, function (e) {
tool.removeClass("over");
setTimeout(function () {
if (!tool.hasClass("over") && !$(".cl-vnavigation li:hover").length > 0) {
tool.hide();
}
}, 500);
});
我尝试使用指令,但是它具有相同的行为,即。最初只有DOM中已经存在的元素会响应点击事件。
为了完整起见,这是指令:
app.directive("testAnchor", function ($compile) {
return {
restrict: "E",
replace: true,
scope: { onClick: '&' },
template: '<a href="#" ng-click="onClick({arg1: string, arg2: string})>TestText!</a>',
link: function (scope, element, attrs) {
$compile(element.contents())(scope.$new());
}
}
});
我这样称呼它:
<test-anchor on-click="myFunction(argument1, argument2)"></test-anchor>
我曾希望AngularJS可以编译附加的指令,但是显然不能那样工作。
那么:加载后AngularJS可以编译由外部库附加的HTML吗?
答案 0 :(得分:1)
也许尝试将angularjs引导到如下创建的动态元素中
UPD:更新处理事件的代码。
var button = $('#action').click(createSomething);
function createSomething() {
$(document.body).append('<div id="dynamic"><div>Dynamic created</div><app-dir></app-dir></div>');
angular.bootstrap(
document.getElementById('dynamic'),
['app']
);
}
angular.module('app', [])
.directive('appDir', appDir);
function appDir() {
return {
restrict: 'E',
template: '<h2 ng-click="clickHandler()">Hello from Angularjs</h2>',
link: appDirLinkFn
};
}
function appDirLinkFn($scope) {
$scope.clickHandler = clickHandler;
function clickHandler() {
console.log('Click from angularjs elememnt');
}
}
#dynamic {
margin: 1rem;
background-color: #ccc;
border-color: #999;
border-radius: 5px;
padding: 1rem;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="action">Create something</button>
答案 1 :(得分:0)
据我了解,事件处理程序未触发click事件的原因是,在定义事件处理程序时,所引用的DOM元素必须已经存在。
由于我不想更新外部库中的代码(即悬停事件处理程序),所以我在Angular控制器中声明了第二个悬停(实际上是:mouseover)事件处理程序。
此事件处理程序将在短暂的延迟(理论上应为其他处理程序添加DOM元素留出足够的时间)之后,为click事件创建第二个事件处理程序。
类似这样的东西:
$scope.registerClickEvent = function () {
if (!$scope.clickEventRegistered) {
setTimeout(function () {
$('.testclass').click(
function (event) {
$scope.someFunction(event);
}
);
},
100);
$scope.clickEventRegistered = true;
}
}
在HTML中,我还将ng-mouseover设置为还监听悬停事件的元素:
<ul class="cl-vnavigation" ng-mouseover="registerClickEvent()"></ul>
.testclass
设置在无序列表内的锚元素上。