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


86

谁能告诉我如何将一个指令中的控制器包含在另一个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指令访问控制器,但是我不能。有更好的方法吗?


5
require确保存在另一个指令,然后包括它的控制器。^require除了当前元素之外,还检查当前元素之上的元素。因此,您必须同时使用这两个指令才能起作用。否则,只需使用定义一个控制器,app.controller然后在两个指令中都使用它。无论哪种方式,您都可以将其与HTML代码一起放入一个简单的Plunker中吗?
乔什·大卫·米勒

Answers:


187

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


这取决于您要通过共享控制器来完成的工作;您可以共享同一控制器(尽管实例不同),也可以共享同一控制器实例。

共享控制器

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

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

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

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

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

需要控制器

如果要共享控制器的相同实例,请使用require

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

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

无论哪种情况,都必须同时使用两个指令。require是组件之间通信的一种方式。

请查看指令指南页面以获取更多信息:http : //docs.angularjs.org/guide/directive


4
是否可能需要同级指令控制器?基本上,我需要在使用ng-repeat重复的兄弟指令之间共享同一个控制器或服务实例(例如,在DOM兄弟中,不在同一DOM元素上)。想象一下,每个重复项都有一条指令,它们之间需要共享状态或逻辑。
CMCDragonkai 2013年

2
@CMCDragonkai无法做到这一点,但是有两种完成同一件事的常用方法。首先是如果兄弟姐妹都是相同的“类型”,则ngRepeat上方的元素可以像容器指令,然后所有子元素都可以要求该指令,而它们共享同一控制器。更常见的解决方案(通常更规范)是使用共享服务。您能否详细说明这些兄弟姐妹的工作以及他们需要分享什么?
乔什·大卫·米勒

是的,最终选择了第一个选项。使用容器指令控制器。效果很好。这是给石工的。
CMCDragonkai 2013年

这是一个很好的答案,巩固了我对所有这些工作原理的理解。谢谢!(请注意,这可能是一个较新的功能,但是您可以require用来指定单个指令或指令数组;每个指令都可以加上caret(^)前缀,以实现更精细的要求。)
jedd.ahyoung

在两个指令中使用相同的控制器不会使每个指令具有其自己的实例。
jsbisht

27

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

需要父指令控制器的AngularJS指令控制器?

链接到这个非常清晰的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';
}

4
对我来说,让马克·拉杰科克(Mark Rajcok)的示例获得最多点击的原因是,它着重于控制器方法的创建方式。通常,您会看到通过$ scope.methodName = function(){...}创建的控制器方法,但要使其正常工作,必须对要访问的方法使用this.methodName。起初我没有注意到。
coblr 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.