如何在 angularjs 指令中要求控制器

Posted

技术标签:

【中文标题】如何在 angularjs 指令中要求控制器【英文标题】:How to require a controller in an angularjs directive 【发布时间】:2013-03-18 08:27:04 【问题描述】:

谁能告诉我如何将一个指令中的控制器包含在另一个 angularJS 指令中。 例如我有以下代码

var app = angular.module('shop', []).
config(['$routeProvider', function ($routeProvider) 
    $routeProvider.when('/', 
        templateUrl: '/js/partials/home.html'
    )
        .when('/products', 
        controller: 'ProductsController',
        templateUrl: '/js/partials/products.html'
    )
        .when('/products/:productId', 
        controller: 'ProductController',
        templateUrl: '/js/partials/product.html'
    );
]);

app.directive('mainCtrl', function () 
    return 
        controller: function ($scope) 
    ;
);

app.directive('addProduct', function () 
    return 
        restrict: 'C',
        require: '^mainCtrl',
        link: function (scope, lElement, attrs, mainCtrl) 
            //console.log(cartController);
        
    ;
);

总的来说,我应该能够访问 addProduct 指令中的控制器,但我不能。有没有更好的方法来做到这一点?

【问题讨论】:

require 确保存在另一个指令,然后包含其控制器。 ^require 除了检查当前元素之外,还会检查当前元素之上的元素。所以你必须同时使用这两个指令才能工作。否则,只需使用app.controller 定义一个控制器,然后在两个指令中使用它。不管怎样,你能把它和你的 HTML 代码一起放到一个简单的 Plunker 中吗? 【参考方案1】:

我很幸运并在对该问题的评论中回答了这个问题,但为了完整起见,我发布了一个完整的答案,因此我们可以将此问题标记为“已回答”。


这取决于你想通过共享控制器来完成什么;您可以共享同一个控制器(尽管有不同的实例),也可以共享同一个控制器实例。

共享控制器

通过将相同的方法传递给两个指令,两个指令可以使用相同的控制器,如下所示:

app.controller( 'MyCtrl', function ( $scope ) 
  // do stuff...
);

app.directive( 'directiveOne', function () 
  return 
    controller: 'MyCtrl'
  ;
);

app.directive( 'directiveTwo', function () 
  return 
    controller: 'MyCtrl'
  ;
);

每个指令都将获得自己的控制器实例,但这允许您在任意数量的组件之间共享逻辑。

需要控制器

如果你想共享一个控制器的同一个instance,那么你使用require

require 确保存在另一个指令,然后将其控制器作为参数包含在链接函数中。因此,如果您在一个元素上有两个指令,则您的指令可以要求另一个指令的存在并获得对其控制器方法的访问权限。一个常见的用例是要求ngModel

^require,添加插入符号后,除了当前元素之外,还会检查指令上方的元素,以尝试找到另一个指令。这使您可以创建复杂的组件,其中“子组件”可以通过其控制器与父组件进行通信以达到很好的效果。示例可能包括选项卡,其中每个窗格都可以与整个选项卡通信以处理切换;手风琴套装可以确保一次只打开一个;等等

在任何一种情况下,您都必须同时使用这两个指令才能使其工作。 require 是组件之间的一种通信方式。

查看指令指南页面了解更多信息:http://docs.angularjs.org/guide/directive

【讨论】:

是否可能需要兄弟指令控制器?基本上,我需要在使用 ng-repeat 重复的兄弟指令之间共享控制器或服务的相同实例(如在 DOM 兄弟中,而不是在同一个 DOM 元素上)。想象一下,每个重复项都有一个指令,需要它们之间共享状态或逻辑。 @CMCDragonkai 没有办法做到这一点,但是有两种常见的方法可以完成同样的事情。第一个是如果兄弟姐妹都是相同的“类型”,那么 ngRepeat 上方的元素可以像一个容器指令,然后所有子元素都可以改为需要该指令,都共享同一个控制器。更常见的解决方案 - 通常更规范 - 是使用共享服务。您能否详细说明这些兄弟姐妹的工作以及他们需要分享的内容? 是的,最终选择了第一个选项。使用容器指令控制器。效果很好。这是砌体的。 这是一个很好的答案,巩固了我对所有这些工作原理的理解。谢谢! (请注意,这可能是一个较新的功能,但您可以使用 require 指定单个指令或指令数组;每个指令都可以使用插入符号(^)作为前缀以获得更精细的要求。) 在两个指令中使用相同的控制器不会给每个指令它自己的实例。【参考方案2】:

Mark Rajcok 在这里有一个很好的 *** 答案:

AngularJS directive controllers requiring parent directive controllers?

带有指向这个非常清晰的 jsFiddle 的链接:http://jsfiddle.net/mrajcok/StXFK/

<div ng-controller="MyCtrl">
    <div screen>
        <div component>
            <div widget>
                <button ng-click="widgetIt()">Woo Hoo</button>
            </div>
        </div>
    </div>
</div>

javascript

var myApp = angular.module('myApp',[])

.directive('screen', function() 
    return 
        scope: true,
        controller: function() 
            this.doSomethingScreeny = function() 
                alert("screeny!");
            
        
    
)

.directive('component', function() 
    return 
        scope: true,
        require: '^screen',
        controller: function($scope) 
            this.componentFunction = function() 
                $scope.screenCtrl.doSomethingScreeny();
            
        ,
        link: function(scope, element, attrs, screenCtrl) 
            scope.screenCtrl = screenCtrl
        
    
)

.directive('widget', function() 
    return 
        scope: true,
        require: "^component",
        link: function(scope, element, attrs, componentCtrl) 
            scope.widgetIt = function() 
                componentCtrl.componentFunction();
            ;
        
    
)


//myApp.directive('myDirective', function() );
//myApp.factory('myService', function() );

function MyCtrl($scope) 
    $scope.name = 'Superhero';

【讨论】:

对我来说,让 Mark Rajcok 的示例点击最多的是关注控制器方法的创建方式。通常,您会看到通过 $scope.methodName = function()... 创建的控制器方法,但为了使其工作,您必须将 this.methodName 用于您想要访问的方法。一开始我没有注意到。

以上是关于如何在 angularjs 指令中要求控制器的主要内容,如果未能解决你的问题,请参考以下文章

AngularJS自定义验证指令 - 如何避免使用隔离范围

AngularJS 和 Typescript:如何将类/类型分配为指令的控制器?

AngularJS:如何将参数/函数传递给指令?

如何使用angularjs将日期格式从控制器传递到指令

AngularJs自定义指令详解 - link

如何从 AngularJS 中的自定义指令 * 使用自己的范围 * 访问父范围?