插件在指令中被调用了数百次

时间:2014-08-12 18:53:51

标签: javascript angularjs angularjs-directive

app.directive('tooltip_plugin_as_example', function() {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
       $(element).tooltip();
       console.log("this is called");
    }
  };
});

<div class="someclass">
    <ul>
        <li tooltip_plugin_as_example ng-repeat="item in iCtrl">{{item.name}}</li>
    </ul>
</div>
单击新选项卡并加载新页面时,

this is called会发生数百次。我希望它只发生一次,理想情况是,加载最后一项。可能吗?我正在考虑设置间隔,例如每秒调用一次这个插件,但很明显,这将是一个可怕的做法......

7 个答案:

答案 0 :(得分:2)

你没有对任何dom事件采取行动,因此“这被称为”将记录现有的每个实例。

也许尝试这个,只有在点击指令时才会运行。

app.directive('tooltip_plugin_as_example', function() {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
       element.bind('click',function(){
       //your code
      });

    }
  };
});

如果我误解了你能用jsfiddle提供更好的解释吗?

答案 1 :(得分:2)

如果您使用的是来自jqueryui的.tooltip()

您似乎无需担心何时呈现最后一个li元素或添加/删除li元素。

只需在父元素上调用.tooltip()一次即可。添加新元素时无需再次调用它。

您可以编写一个简单的指令来调用.tooltip()

.directive('tooltip', function () {
  return {
    restrict: 'A',
    link: function (scope, element) {
      element.tooltip();
    }
  };
})

并将其放在父元素上:

<ul tooltip>
  <li ng-repeat="item in iCtrl" title="{{item.name}}">{{item.name}}</li>
</ul>

或者如果你想要整个页面的工具提示,你可以只调用一次。

$document.tooltip();

示例Plunker: http://plnkr.co/edit/qNQFnoW4uRzKmEoIH81l?p=preview

希望这有帮助。

答案 2 :(得分:2)

这取决于您正在使用的插件以及您要应用的范围(在页面的一个部分或整个页面上,......)

1)如果您的插件要求您在不同参数的每个元素上调用它,那么使用它就像在代码中一样,只需记住清理以避免泄漏:

app.directive('tooltip_plugin_as_example', function() {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
       element.tooltip(); //don't need to wrap inside $()

       scope.$on("$destroy",function(){
          //cleanup your tooltip here. 
          //Example code with jQuery tooltip:
          //element.tooltip("destroy");
       }
    }
  };
});

当您的集合更改并删除了一些项目时,ng-repeat将销毁这些项目的范围,并在这些范围上触发$destroy事件,允许在角度将其从DOM中删除之前进行清理。

2)如果您的插件可以在父元素上调用,则将相同的行为应用于其所有子元素。您可以像@ runTarm的答案一样使用它。还记得清理以避免泄漏。

答案 3 :(得分:1)

找到答案(不确定它是否最好,但效果很好)

app.directive('tooltip_plugin_as_example', function() {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
       if (scope.$last)
       {
         $('.elementClass').tooltip(); 
         console.log("happens once");
       }
    }
  };
});

答案 4 :(得分:1)

在指令中使用compile函数而不是link函数来避免这些100的调用。 ng-repeat将采用已克隆编译的元素。

根据AngularJS文件: -

  

某些指令,例如ng-repeat克隆DOM元素,每个指令一次   集合中的项目。改进了编译和链接阶段   因为克隆模板只需要编译一次,   然后为每个克隆实例链接一次。

在ng-repeat上使用编译函数时,只能执行一次编译该代码的性能优势。

如果您使用tooltip()中的jQueryUI

来自tooltip()

jQueryUI插件将添加也将被克隆的侦听器等,但我可能建议使用来自tooltip项目的Angular UI Bootstrap指令,这将确保正确销毁侦听器

答案 5 :(得分:1)

如果你想检查ng-repeat中的最后一个元素,你可以这样做:

app.directive('tooltipPluginAsExample', function() {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
        var isLast = attrs.tooltipPluginAsExample;

        if (isLast == 'true') {
            console.log('last element!');
        }
    }
  };
});

在html中你需要使用ng-repeat指令提供的$ last变量(doc:https://docs.angularjs.org/api/ng/directive/ngRepeat):

<div ng-controller="ItemCtrl">
    <ul>
        <li tooltip-plugin-as-example="{{$last}}" ng-repeat="item in iCtrl">{{item.name}}</li>
    </ul>
</div>

jsFiddle示例:http://jsfiddle.net/nzuru5a9/4/

答案 6 :(得分:1)

您只需要检查指令中的ngRepeat $last属性

app.directive('tooltip', function() {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
      if(scope.$last) {
        //$(element).tooltip();
        console.log("this is called for index:");
        console.log(scope.$index); // check for last index of ngRepeat
      }
    }
  };
});

使用$index使用JSBin检查它是否仅在最后一个元素上调用:http://jsbin.com/pavefe/1/