【问题标题】:ng-hide breaking my directive in angular 1.3.16ng-hide 在 Angular 1.3.16 中破坏了我的指令
【发布时间】:2015-06-20 14:16:40
【问题描述】:

我正在尝试从 angular 1.2.28 迁移到 angular 1.3.16,但是我的代码坏了。

Angular 1.2.28 工作:http://plnkr.co/edit/XfVakwA3Upm7Z2wosHCQ?p=preview

Angular 1.3.16 不工作:http://plnkr.co/edit/4VxcHL0MHddobkmu9DMG?p=preview

JS

var app = angular.module('app', []);
app.run(function($rootScope, $timeout){
  $rootScope.loading = true;
  $timeout(function(){
    $rootScope.items = ['Angular', '1.3.16', 'doesnt work'];
    $rootScope.loading = false;
  }, 3000);
});

app.directive('refresh', function(){
  return {
    restrict: 'A',
    require: '^myDirective',
    link: function(scope, element, attrs, ctrl){
      if(scope.$last)
        ctrl.init();
    }
  };
});

app.directive('myDirective', function(){
  return {
    restrict: 'E',
    replace: true,
    transclude: true,
    template: '<div class="my-directive"><p>Height: {{myHeight}}</p> <div ng-transclude></div></div>',
    controller: function($scope, $element){
      this.init = init;

      function init(){
        $scope.myHeight = $('.my-directive').height();
      }
    }
  };
});

HTML

<!DOCTYPE html>
<html ng-app="app">

  <head>
    <script data-require="angular.js@1.3.16" data-semver="1.3.16" src="https://code.angularjs.org/1.3.16/angular.js"></script>
    <script data-require="jquery@1.11.0" data-semver="1.11.0" src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
    <link rel="stylesheet" href="style.css" />
    <script src="script.js"></script>
  </head>

  <body>
    <h1>Angular 1.3.16</h1>
    <div ng-show="loading">Loading...</div>
    <my-directive ng-hide="loading">
      <div ng-repeat="item in items" refresh>
        <p>{{item}}</p>
      </div>
    </my-directive>
  </body>

</html>

这个想法是只在输出内部 html 时运行某些代码。 高度为 0,角度为 1.3.16。

但是,如果我在角度 1.3.16 中从 &lt;my-directive ng-hide="loading"&gt; 中删除 ng-hide="loading",高度将获得适当的值。

有什么办法可以解决这个问题吗?

【问题讨论】:

  • 不知道为什么它不再起作用了,但我觉得这种做法相当复杂。这是一个修改后的例子,做同样的事情(并且工作):plnkr.co/edit/ULkWW8Ir75EJ0RfMHsau?p=preview。注意:包含 jquery before angular,使用 ng-if 而不是 ng-hide 仅在加载完成后执行指令,使用元素而不是类选择器。
  • 嗨,$timeout 有点小技巧,你不是说吗?你说“我觉得这种做法很复杂”,那我该如何改进我写的代码呢?
  • 是的,这有点小技巧。但是我发现它比依赖于调用第一个函数的附加指令要少得多,如果范围恰好具有真实的 $last 属性,因为嵌入的模板恰好使用 ng-repeat。我的代码不需要任何其他指令,并且无论嵌入的模板是什么都可以工作。存在超时,以便在浏览器呈现指令后计算高度。
  • 那么,你知道我该如何重写这个吗?没有 $timeout 并且与我所做的不同?我真的很感激。
  • 如果我知道如何避免 $timeout 黑客攻击,我会避免它。不幸的是,这是我所知道的最干净的解决方案。这也是stackoverflow.com/questions/11125078/…中所建议的。

标签: angularjs


【解决方案1】:

$timeout 注入您的指令并将初始化代码块放入 $timeout(function(){ ... }) 中,如下所示:

app.directive('myDirective', function($timeout){
  return {
    restrict: 'E',
    replace: true,
    transclude: true,
    template: '<div class="my-directive"><p><b>Height: {{myHeight}}</b></p> <div ng-transclude></div></div>',
    controller: function($scope, $element){
      this.init = init;

      function init(){
        $timeout(function(){
          $scope.myHeight = $('.my-directive').height();
        });
      }
    }
  };
});

【讨论】:

    【解决方案2】:

    var app = angular.module('app', []);
    app.run(function($rootScope, $timeout) {
      $rootScope.loading = true;
      $timeout(function() {
        $rootScope.items = ['Angular', '1.3.16', ' work'];
        $rootScope.loading = false;
      }, 1000);
    });
    
    
    app.directive('myDirective', function($timeout) {
      return {
        restrict: 'E',
        replace: true,
        transclude: true,
        template: '<div class="my-directive"><p>Height: {{myHeight}}</p> <div ng-transclude></div></div>',
        link: function($scope, $element) {
    
          $element.on('DOMAttrModified DOMSubtreeModified', init);
    
          function init() {
            $scope.$apply(function() {
              $scope.myHeight = $element.height();
            });
          }
        }
      };
    });
    <!DOCTYPE html>
    <html ng-app="app">
    
    <head>
      <script data-require="jquery@1.11.0" data-semver="1.11.0" src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
      <script data-require="angular.js@1.3.16" data-semver="1.3.16" src="https://code.angularjs.org/1.3.16/angular.js"></script>
      <link rel="stylesheet" href="style.css" />
      <script src="script.js"></script>
    </head>
    
    <body>
      <h1>Angular 1.3.16</h1>
      <div ng-show="loading">Loading...</div>
      <my-directive ng-hide="loading">
        <div ng-repeat="item in items" refresh>
          <p>{{item}}</p>
        </div>
      </my-directive>
    </body>
    
    </html>

    您必须在正确的角度指令阶段/生命周期中设置高度。您应该在 link 甚至 postlink 阶段设置高度。如果您不使用 prelink,通常这两个阶段是相同的,此时所有内容都已呈现。见angular $compile 或谷歌angular post link

    controller 用于逻辑,link 用于 html/dom 操作。

    编辑: 您可以绑定 'DOMAttrModified DOMSubtreeModified` 事件来触发更改。

    【讨论】:

    • 你好,我一直不喜欢这个refresh directive,但我不知道如何才能写得更好。每当我写一个 transclude 指令并且它的内容有一个 ng-repeat 时,我总是必须写一些 refresh directive 就像我所做的那样,以便知道什么时候 transclude 内容完成渲染。老实说,我从来没有找到过这样的例子……你有吗?
    猜你喜欢
    • 2017-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-23
    • 1970-01-01
    • 2021-07-05
    • 1970-01-01
    相关资源
    最近更新 更多