【问题标题】:Can AngularJS compile HTML appended by an external library after load?加载后AngularJS可以编译由外部库附加的HTML吗?
【发布时间】:2019-02-13 10:15:17
【问题描述】:

我们的网络应用程序目前有一个可折叠的侧边菜单,其逻辑是通过一个名为 CleanZone 的外部库处理的。 加载子菜单项时会出现问题。当菜单折叠时,这些会在页面加载后附加到 DOM,导致单击事件处理程序(通过 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 吗?

【问题讨论】:

    标签: javascript jquery html angularjs


    【解决方案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>

    【讨论】:

    • 这个答案在动态创建的元素中没有点击事件处理?
    • 更新了答案中的代码。现在点击Hello from Angularjs
    • 这个的另一个问题是我需要更新外部库的代码来调用angular.bootstrap。我不想这样做,我必须以某种方式将 AngularJS 订阅到某种 DOM 附加事件,然后调用我猜的引导函数。我尝试了此处列出的 angular-dom-events 方法,但它对我不起作用(仍然是相同的行为)stackoverflow.com/questions/21332671/angularjs-watch-dom-change
    • 您能否提供您使用的有关cleanZones 的资源的链接?可能,在它的 api 中需要机会。
    • 我找到了解决问题的方法,将为它创建一个单独的答案
    【解决方案2】:

    据我了解,事件处理程序未触发 click 事件的原因是,所引用的 DOM 元素在定义事件处理程序时必须已经存在。

    由于我不想更新外部库中的代码(即悬停事件处理程序),因此我在我的 Angular 控制器中声明了第二个悬停(实际上:鼠标悬停)事件处理程序。

    此事件处理程序将在短暂延迟后为单击事件创建第二个事件处理程序(理论上这应该为其他处理程序留出足够的时间来附加 DOM 元素)。

    类似这样的:

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

    【讨论】:

      猜你喜欢
      • 2014-03-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-31
      • 2014-07-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多