简体   繁体   English

AngularJS - 指令事件和 DOM 渲染

[英]AngularJS - Directive events and DOM rendering

In the code below, I am trying to use a template (with {{ value }} substitution) but I have been trying for two days to find a way of getting to the rendered code to set some properties on it.在下面的代码中,我试图使用一个模板(带有{{ value }}替换),但我已经尝试了两天来找到一种获取呈现代码以在其上设置一些属性的方法。

I cannot use the style selector (which works fine), I need to use the div's id.我不能使用样式选择器(工作正常),我需要使用 div 的 id。 In my real code I use a templateUrl: , not the inline code, but it has the same result.在我的实际代码中,我使用了templateUrl: ,而不是内联代码,但它具有相同的结果。

Which event should I be listening for?我应该收听哪个事件? At what point in time will the selectors work?选择器将在什么时间点起作用? I have read about compiling and linking and think the answer is out there somewhere?我已经阅读了有关编译和链接的内容,并认为答案就在某个地方?

Thanks in advance ...提前致谢...

<!doctype html>
<html lang="en" ng-app="myApp">
   <head>
      <meta charset="utf-8">
      <title>My AngularJS App</title>
      <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
   </head>
   <body style="height:100%; width: 100%;">
      <tls-window window-id="fred" window-width="600" window-label-width="150"></tls-window>
      <script src="lib/angular/angular.js"></script>
      <script src="js/app.js"></script>
      <script src="js/core/services.js"></script>
      <script src="js/core/controllers.js"></script>
      <script src="js/core/filters.js"></script>
      <script src="js/core/directives.js"></script>
      <script src="js/core/tlscore-directives.js"></script>
      <script type="text/javascript">

      var coreDirectives = angular.module('tlsCore.directives', []);
      coreDirectives.directive('tlsWindow', function() {
        return {
          restrict: 'E',
          scope: {
            windowId: '@windowId',
            windowWidth: '@windowWidth',
            labelWidth: '@windowLabelWidth'
          },
          replace: true,
          transclude: false,
          template: '<div id="{{windowId}}" class="tls-window" ng-cloak tls-draggable >' +
            '<div id="{{windowId}}-winBackground" class="tls-window-background" style="width: 300px; height: 200px" >' +
            '<div id="{{windowId}}-winToolbarBackground" class="tls-window-toolbar-background">' +
            '<div id="{{windowId}}-winToolbarContent" class="tls-window-toolbar-content" style="width: 300px; height: 100px">' +
            '</div>' +
            '</div>' +
            '</div>',
          link: function(scope, element, attrs) {
            var ele = element.get(element.index(scope.windowId));
            // this works and sets the colour (by class)
            $('.tls-window-toolbar-content').css("background-color", 'red');
            // this does not work as the id of the element is not yet substituted and rendered ??
            $('#fred-winBackground').css("background-color", 'green');
          }
        }
      });   

      </script>
   </body>
</html>

Option 1 - Better选项 1 - 更好

Instead of using the template method, move the HTML into the link method.不要使用template方法,而是将 HTML 移动到link方法中。 This enables us to manually $interpolate the bracketed terms before compiling, and then use the ID selector.这使我们能够在编译之前手动$interpolate括号内的术语,然后使用 ID 选择器。 Note that this would not be possible without using the = instead of @ isolate scope binding, because @ bindings are postponed until later and are undefined in the link method (See more on that here ).请注意,这不会不使用有可能=代替@分离范围结合,因为@绑定推迟到后面,并在是不确定的link方法(更多的见这里)。

app.directive('tlsWindow', function($interpolate,$compile) {
  return {
    restrict: 'E',
    scope: {
        windowId: '=',
        windowWidth: '=',
        labelWidth: '='
    },
    link: function (scope, element, attrs) {
        var template = '<div id="{{windowId}}" class="tls-window" ng-cloak tls-draggable >' +
        '<div id="{{windowId}}-winBackground" class="tls-window-background" style="width: 300px; height: 200px" >' +
            '<div id="{{windowId}}-winToolbarBackground" class="tls-window-toolbar-background">' +
                '<div id="{{windowId}}-winToolbarContent" class="tls-window-toolbar-content" style="width: 300px; height: 100px">' +
                '</div>' +
            '</div>' +
        '</div>';

        var interpolated = $interpolate(template)(scope);
        var html = $(interpolated);
        element.replaceWith($compile(html)(scope));
        
        $('.tls-window-toolbar-content').css('background-color', 'red');
        $('#fred-winBackground').css('background-color', 'green');
    }   
  }
}); 

Here is a fiddle这是一个小提琴


Option 2选项 2

Not the most robust solution but this would work also.不是最强大的解决方案,但这也可以。 Here the manipulation is postponed until after the rendering by using $timeout .在这里,使用$timeout将操作推迟到渲染之后。 This causes a slight delay as well.这也会导致轻微的延迟。

$timeout(function(){
    $('#fred-winBackground').css("background-color", 'green');
},0);

This requires $timeout to be injected into the directive as well.这也需要将$timeout注入指令中。

I see you have an answer about why the id isn't available at link time, but might I question the reason to use an id selector at all?我看到你有一个关于为什么在链接时 id 不可用的答案,但我可以质疑完全使用 id 选择器的原因吗? Once you have your directive, you can get access to the top level div in your template via the children method of the jqLite/jquery element in the link function.获得指令后,您可以通过链接函数中 jqLit​​e/jquery 元素的children方法访问模板中的顶级 div。 See this example:看这个例子:

 angular.module('myApp', []) .directive('tlsWindow', function() { return { restrict: 'E', scope: { windowId: '@windowId', windowWidth: '@windowWidth', labelWidth: '@windowLabelWidth' }, replace: true, transclude: false, template: '<div id="{{windowId}}" class="tls-window" ng-cloak tls-draggable >' + '<div id="{{windowId}}-winBackground" class="tls-window-background" style="width: 300px; height: 200px" >' + '<div id="{{windowId}}-winToolbarBackground" class="tls-window-toolbar-background">' + '<div id="{{windowId}}-winToolbarContent" class="tls-window-toolbar-content" style="width: 300px; height: 100px">' + '</div>' + '</div>' + '</div>', link: function(scope, element, attrs) { // var ele = element.get(element.index(scope.windowId)); // this works and sets the colour (by class) // $('.tls-window-toolbar-content').css("background-color", 'red'); // this does not work as the id of the element is not yet substituted and rendered ?? // $('#fred-winBackground').css("background-color", 'green'); // Use the jqlite or jquery children method to locate the first child of your directive // element (from linkFn) is the element of tls-window and children() gets you access to the <div> container in your template element.children().css("background-color", "green"); } } });
 <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script> <div ng-app="myApp"> <tls-window window-id="fred" window-width="600" window-label-width="150"></tls-window> </div>

angularjs discourages referencing elements through id selectors. angularjs 不鼓励通过 id 选择器引用元素。 Make use of jqLite/jquery methods through the context of element that is passed to the link function.通过传递给链接函数的元素上下文来使用 jqLit​​e/jquery 方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM