【问题标题】:Transcluding ng-click in a directive在指令中包含 ng-click
【发布时间】:2014-01-23 07:31:54
【问题描述】:

我正在构建一个 AngularJS 指令。我希望该指令包装其中包含 ng-click 的其他内容。单击时生成的按钮不执行任何操作。 这是我尝试过的代码的简化版本:

(HTML)

<div ng-app="someapp">
    <div ng-controller="Ctrl1">
        <h2>Example</h2>
        <my-dir data-x="1">
            <button ng-click="refresh()" id="refresh1">Refresh</button>
        </my-dir>
        <my-dir data-x="2">
            <button ng-click="refresh()" id="refresh2">Refresh</button>
        </my-dir>
    </div>
</div>

(JavaScript)

var app = angular.module('someapp', []);

app.controller('Ctrl1', function($scope){ });

app.directive('myDir', function(){
    return {
        restrict: 'E',
        scope: {},
        template: '<div><p>Directive contents:</p><div ng-transclude></div></div>',
        transclude: true,
        link: function(scope, element, attrs){
            $scope.y = attrs.x+1;
            scope.refresh = function(){
                console.log("Refresh Called, y = ", $scope.y);
            }
        }
    };
});

如何更改它以使按钮真正触发 $scope.refresh() 函数?

补充说明:

我需要指令的本地对象信息(单个控制器中可以有多个该指令),因此我创建了一个新范围。

【问题讨论】:

    标签: javascript angularjs angularjs-directive


    【解决方案1】:

    正如 dcodesmith 所指出的,嵌入的 ng-click 将绑定到控制器的范围而不是指令的范围。根据您到底想要做什么,您可能希望这是行为(因为被嵌入的内容不是指令的一部分,为什么要调用指令范围内的方法?)。就个人而言,我会改为在控制器的范围内声明该方法。

    app.controller('Ctrl1', function($scope){ 
        $scope.refresh = function() {
            console.log("Refresh called.");
        };
    });
    

    在这种情况下,您的指令应该声明隔离范围,即使其中没​​有任何内容。

    更新:根据您的评论,为什么不在指令模板中包含按钮?在这种情况下,它已经与正确的范围相关联。

    如果在某些情况下您不需要刷新按钮,则通过指令将其作为选项公开为属性:

    <my-dir show-button='true'></my-dir>
    
    // directive scope
    scope: {
        showButton: '='
    } 
    

    这种方法最大的问题是使用“双向绑定”运算符 (=) 导致“真”和“假”被视为表达式。我只是不太喜欢那种感觉。

    无论如何,希望这可以解决您的问题... 还有一条评论,我说这甚至不知道您正在实施的是否实际上是一个刷新按钮,但如果是,我会花一点时间考虑您是否真的需要一个“刷新”按钮。 Angular 擅长消除刷新按钮!

    更新 2:

    我创建了一个 plunkr,显示我认为我会如何处理您的情况,尤其是在任何杂项控件被重复使用的情况下:

    http://plnkr.co/edit/FhrSwcrSZScvCfhtCSjn

    在本例中,两个按钮指令实际上是“videoPlayer”指令的子指令。它们的逻辑包含在该指令中,但它们是单独实例化的,并且不需要父指令操作。 “父指令”(视频播放器)只是公开 API 以供“子”使用。也不是父级的方法是构造函数的方法,而不是范围。我认为这很奇怪,但它完全取自 angular 文档:

    http://docs.angularjs.org/guide/directive(页面上的最后一个示例)

    请注意,每个 videoPlayer 指令仍然有自己的隔离范围。

    【讨论】:

    • 我并没有将指令锁定到单个控制器;我正在绘制可以在我的应用程序的任何地方使用的图表。
    • 我已根据您的评论更新了我的答案。在您的其他评论中,我不确定我是否完全理解这个问题。像您一样使用“隔离”范围,您可以在同一个控制器中拥有任意数量的该指令实例 - 它们的范围是隔离的。您是在谈论在指令之间共享数据吗?
    • 我知道我需要使用 Isolate 范围。我的另一条评论是我确认我不能只继承范围。我对每个指令都有很多杂项控件(在线视频播放器上的思考按钮,图形控件除外)。是的,我意识到 Angular 可以很好地处理刷新。只有一种情况我无法避免(因此我需要那个特定的按钮)。不过,我可能可以让它使用更多的属性。谢谢!
    • 谢谢你,“转入的内容不是指令的一部分,为什么要调用指令范围内的方法?”
    • 您好,5 年后 - 只是想说谢谢(更新 2),它拯救了我的理智!
    【解决方案2】:

    删除scope 对象。那里似乎发生了冲突。

    摘自Creating a Directive that Wraps Other Elements

    transclude 选项改变了范围嵌套的方式。它使嵌入指令的内容具有指令外部的任何范围,而不是内部的任何范围。这样做时,它使内容可以访问外部范围。

    app.directive('myDir', function(){
        return {
            restrict: 'E',
            //scope: {}, remove this line.
            template: '<div><p>Directive contents:</p><div ng-transclude></div></div>',
            transclude: true,
            link: function(scope, element, attrs){
                console.log("X-attr", attrs.x);
                scope.refresh = function(){
                    console.log("Refresh Called");
                }
            }
        };
    });
    

    【讨论】:

    • 添加了一些导致问题的附加信息:如果控制器中有多个相同的指令需要本地范围怎么办?
    • 指令上的link 函数提供了一个transclude 参数,该参数可以提供对嵌入HTML 的访问:angular-tips.com/blog/2014/03/transclusion-and-scopes
    猜你喜欢
    • 2020-07-12
    • 2014-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-17
    • 1970-01-01
    • 2017-11-14
    • 1970-01-01
    相关资源
    最近更新 更多