javascript template标签 如何在不覆盖父范围的情况下将参数传递给一个指令?




vue.component (8)

如果你想用in指令使用控制器作用域,你应该做以下的事情

app.directive('fixedColumnTooltip', function ($timeout) {
return {
    restrict: 'A',

    link: function (scope, element, attr) {
      var columnselector = attr.columnselector;
      console.log(scope[columnselector]);
    }
}});

这不会为指令创建任何范围,您仍然可以访问columnselector的值。 如果你想在columselector中传递函数,那么你可以做$ parse(attr.columnselector)。如果它的值是$ parse则不需要。

我需要创建一个指令,该指令作用于使用ng-repeat呈现表格行的表单元格 - 为此,我已经部分地依赖于题为“在ng-repeat完成时调用函数”的问题的答案 。 然而,与问答不同的是,我需要将一个论点传递给我的指令,为此,我部分依赖了这个答案 (题目为“Angularjs - 通过指令的论证”)。

所以在我的情况下,我已经为我的指令添加了fixed-column-tooltip ,并将columnselector作为它的参数添加到<tr> ,如下所示:

<tr fixed-column-tooltip columnselector=".td-keyField" ng-repeat="trData in trDataWatch">

但是当第二个答案中,我增加了我所学到的是一个“隔离范围”到我的指令,我不再有权按照第一个答案访问原始范围:

'use strict';

angular.module('cmt.cases.directives')

.directive('fixedColumnTooltip', function ($timeout) {
    return {
        restrict: 'A',
        scope: {
            columnselector: '@'
        },
        link: function (scope, element, attr) {
            if (scope.$last === true) { //undefined because not operating on original scope
        ...

有没有办法保持访问原始范围,但也有权访问columnselector参数?


Answer #1

也许有点难看,但工作:获取当前指令的DOM元素,向后遍历其父元素,使其成为一个角元素,调用内置的scope()函数,例如

link: function (scope, elem) {
  var parentScope = angular.element ($(elem).parent()).scope();
  console.log (parentScope)
}

Answer #2

好吧,首先,因为你正在使用隔离范围,并不意味着你不能访问父范围内的东西。 隔离范围旨在限制您默认获得的内容,但是您可以从父范围指定任何您想要的内容。 正确的做法是使用“parentScopeVariable:'='”在你的指令中设置一个双向绑定。 原谅我在手机上的可怕的格式,我想去睡觉:-)。

所以是的,就像你说的那样,你也可以使用“attrs”参数。 甚至有一些棘手的$ eval方法可以在父级作用域上设置只作为attrs传入的东西。 无论如何,你不能在一个给定的元素/组件上使用隔离作用域的指令,所以当你使用隔离作用域时你确实需要小心。 它绝对有助于清洁设计,因为你必须仔细考虑你在指令中使用什么。 要点是,在我看来,有时依靠善意是好的和必要的。 不可否认的是,它确实感觉有些ha or或什么(思考代码的味道),但是我不认为这是一个很好的例子。

最后,我在Angular API doc站点上花了很多时间,在那里有很多好东西。 在$ compile服务页面上有一个非常好的指令引用。 再次,移动,对不起。 如果我在一台完整的计算机上,我会做很好的代码块,并链接指令ref,对不起:-)。 快速谷歌,你会发现它。

所以你绝对可以使用隔离作用域,并且有方法将函数调用传递给一个指令,将指令函数引用从一个指令中传回,返回给一个控制器,双向数据绑定等等。隔离作用域对所有但是这听起来不像你想要做太复杂的事情。


Answer #3

触摸父范围可能不是最好的主意(我的意思是这是不是角度的方式来访问不同的层),更好的有一些额外的scope.models。 无论如何,这是一个简单的工作演示。

angular.module('app', [])
.controller('ctrl', function($scope){
  $scope.trDataWatch = ['item1', 'item2', 'item3'];
  $scope.state = 'unrendered';
  $scope.$on('ngRepeatFinished', function(){
     $scope.state = 'ngRepeatFinished';
  });
})
.directive('fixedColumnTooltip', function ($timeout) {
    return {
        restrict: 'A',
        scope: {
          columnselector: '@',
          first: '=?',
          middle: '=?',
          last: '=?',
          index: '=?',
          odd: '=?',
          even: '=?',
          
        },
        link: function (scope, element, attr) {
          if(scope.last){
              scope.$emit('ngRepeatFinished');
          }
        }
    };
});
td {
  display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
  <h4>{{state}}</h4>
  
<table>
  <tr fixed-column-tooltip columnselector=".td-keyField"
      ng-repeat="trData in trDataWatch"
      index="$index"
      odd="$odd"
      even="$even"
      first="$first"
      middle="$middle"
      last="$last">
    <td>{{trData}}</td>
  </tr>
</table>
</div>

但我强烈建议你重新设计逻辑

据我所知,你想显示span只是为更广泛的td ,你应该肯定使用另一个指令,第二,需要第一个指令,以便您可以使用它的控制器逻辑,或其他。 无论如何 - 更好的设计会帮助你更好,所以你最好更深思


Answer #4

在HTML模板的Angular框架中,您可以访问父范围..

例如:

<div ng-model="$parent.$parent.theModel"></div>

当你在模板中创建新的范围时,这是有效的,例如ng-repeat等等。 理论上你可以使用它来访问你想要使用的父范围。


Answer #5

尽管Angular几乎是全新的,但是我正在回答自己的问题,但仍然希望得到更多的答案,以便我解决问题的方式不被认为是“惯用的”Angular。

具体来说,我没有使用隔离作用域,而是在下面的代码中使用了第三个attrs (attributes)链接/函数参数,否则将新的columnselector属性和我的指令一起得到html。 这是一个普遍接受的做法吗?

'use strict';

angular.module('cmt.cases.directives')

.directive('fixedColumnTooltip', function ($timeout) {
    return {
        restrict: 'A',
        link: function (scope, element, attrs) {
            if (scope.$last === true) {
                $timeout(function () {
                    element.parent().find(attrs.columnselector).each(function() {
                        var td = $(this);
                        var span = td.find('span');

                        if (span.width() > td.width()){
                            span.attr('data-toggle','tooltip');
                            span.attr('data-placement','right');
                            span.attr('title', span.html());
                        }
                    });
                });
            }
        }
    }
});

附录:从评论中可以看出,尽管尝试了几种不同的方法,但仍无法从此答案中获取代码。 如果我在整合这个答案方面做错了,请告诉我。

与此同时,我找到了另外一种方式来做到这一点,但这几乎肯定是一种“代码味道”,而不是利用attrs论点。 具体来说,我发现我可以使用隔离范围,然后访问该范围的$parent范围属性。 然后,我会开始我的代码如下,但我不是主张这一点,而是只是注意到,因为似乎TMTOWTDI(有多种方法来做到这一点)肯定适用于Angular:

'use strict';

angular.module('cmt.cases.directives')

.directive('fixedColumnTooltip', function ($timeout) {
    return {
        restrict: 'A',
        scope: {
            columnselector: '@'
        },
        link: function (scope, element, attrs) {
            if (scope.$parent.$last === true) {
                $timeout(function () {
                    element.parent().find(scope.columnselector).each(function() {
                    ...

Answer #6

只是。 在你的链接函数中使用你的属性参数...

link: function(scope, element, attributes, ctrl) {
  var selector = attributes.columnselector;
}

我不知道为什么我读了广泛的答案,认真的人。


Answer #7

你可以使用,

'use strict';

angular.module('cmt.cases.directives')

.directive('fixedColumnTooltip', function ($timeout) {
    return {
        restrict: 'A',
        scope: {
            columnselector: '@',
            $last: '=$last',
        },
        link: function (scope, element, attr) {
            if (scope.$last === true) {
            ....

范围的第二个参数将通过引用传递$ last参数。

编辑:

由于$ last只能在repeat元素的范围内使用,所以可以从元素范围中获取它,就像这样

'use strict';

angular.module('cmt.cases.directives')

.directive('fixedColumnTooltip', function ($timeout) {
return {
    srestrict: 'A',
    scope: {
        columnselector: '@',
    },
    link: function (scope, element, attrs) {
      var elemScope = element.scope();
      if (elemScope.$last){
             ......
      }          
    }
}




angular-directive