加载后,AngularJS可以编译由外部库附加的HTML吗?

时间:2019-02-13 10:15:17

标签: javascript jquery html angularjs

我们的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吗?

2 个答案:

答案 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设置在无序列表内的锚元素上。