指令可以继承控制器和隔离范围吗?

时间:2015-12-17 20:03:47

标签: angularjs

我的应用程序有一个主控制器," AppCtrl as ac&#34 ;,它包含许多有用的实用程序功能以及我想要轻松访问的信息,例如登录用户' s用户身份。目前ac可以从所有视图访问,因此一切都很棒。

然而,我现在试图摆弄指令,但我遇到了麻烦。我制作了一个简单的指令,需要访问ac中的函数/数据。然而,与此同时,看起来我需要使用隔离范围,因为我计划在视图中多次使用该指令,传递稍微不同的信息。我不想给它一个新的控制器,因为我想访问主AppCtrl的数据。

关于我如何做到这一点的任何建议?我是角色和MVC范例的新手,所以如果我做错了,请告诉我。

谢谢!

3 个答案:

答案 0 :(得分:1)

您可以通过多种方式将值传递到角度中的孤立范围内,尽管其中没有一种方法可以使用。

标准解决方案:"参数化"你的孤立范围

在JS中:

myModule
    .controller('AppController', function AppController() {
        this.myFunction = function myFunction() {
            console.log('Hello from myFunction!');
            return 2;
        };
        this.myData = 40;
    })
    .directive('myDirective', function () {

        return {
            // isolate scope!
            scope: {
                restrict: 'E',
                twoWayData: '=data',
                evaluateExpression: '&expression'
            },
            template: '<span>{{ twoWayData + evaluateExpression() }}</span>'
            // no controller! no link function! no nothing
        };

    });

在标记中:

<div ng-controller="AppController as ac">
    <my-directive data="ac.myData" expression="ac.myFunction()">
    </my-directive>
</div>

如果我没弄错的话,你的问题应该得到回答。

Dumdum解决方案:$scope.$parent

即使你的范围是孤立的(d),它仍然可以使用$scope.$parent访问外部范围(你不能再谈论&#34;父范围&#34;了)。除了使用$parent属性保持对它的引用之外,真正的子作用域只是从父作用域继承原型(原型??)。隔离范围仅具有$parent属性。

不要使用这个&#34;解决方案&#34;。它破坏了封装,你不知道你将要走多远的链(你需要找到多少父母的父母去找你需要的房产?)它显示出糟糕的设计。我能想到的唯一用途就是当你可以建立某种合同时,你的指令只应该用在可以指望具有某些属性的$scope.$parent的上下文中,如

var p = $scope.$parent;
if (!(typeof p.foo === 'function' && typeof p.data === 'object')) {
    throw new Error('Illegal!');
}
// Otherwise go on with business

但即便如此,这应该是你最后的选择。我已经和棱角分明了很多工作,而且我从来没有像这样检查它的外部范围。

伪装的Dumdum解决方案:服务

你可以指望一个子指令的控制器实例化的时间晚于作用域链上的控制器,反之则是链接函数(angular遍历DOM并实例化控制器预订并在命令后运行链接函数) )。因此,如果您将数据提供给AppController中的服务,则可以指望它存在于myDirective中:

myModule
    .factory('MyService', function myServiceFactory() {
        return {
            a: null,
            b: null
        };
    })
    .controller('AppController', [ 'MyService', function AppController(MyService) {
        MyService.a = 'foo';
        MyService.b = 'bar';
    }])
    .directive('myDirective', function () {

        return {
            scope: {
                restrict: 'E'
            },
            controller: ['MyService', function MyDirectiveController($scope, MyService) {
                $scope.a = MyService.a;
                $scope.b = MyService.b;
            }],
            template: '<span>{{ a + b }}</span>'
        };

    });

这看起来很愚蠢。但这实际上是一些人在范围树中的某个点创建数据时所做的事情,并且在链中需要9个范围和3个隔离层。

让我们面对现实:服务是全球化的,你所谓的服务并不重要。如果您将服务视为您在树中的某个点建立的某种上下文并且不会疯狂地脱离上下文,那么从工程角度来看,这才有意义。

其他解决方案

您可以在指令定义对象中使用require。它比使用$scope.$parent更不强大,因为你的指令对于与外部作用域相关的控制器并不是不可知的。

你可以不再肛门给所有的指令一个独立的范围!而是明智地使用scope: truescope: false

如果您使用ui-router,您甚至可以使用状态来定义&#34; contexts&#34;在哪个状态控制器中将注入已解析的数据,或者您可以从$state服务(及其data属性)获取数据,这比从创建的随机服务获取数据要好一些全球化。

答案 1 :(得分:0)

将所有重要功能放入角度服务,并将登录的用户信息放入$ rootScope。

然后将服务和$ rootScope注入控制器以获取指令。

如果你真的很懒,你可以把所有东西放到$ rootScope中而不用担心服务,但我不建议你这样做。

答案 2 :(得分:0)

你想要这样的东西吗?

在javascript中

 (function(){

    angular
    .module('exampleApp', []);

    angular
     .module('exampleApp')
     .controller('ExampleController', Controller);

    function Controller(){
        var vm = this;

        vm.coolMethod = coolFn;
        vm.anotherMethod = anotherFn;
        vm.variableToDirective = "value";

        function coolFn(){
            alert('function cool');
        }

        function anotherFn(){
            alert('another function');
        }
    }

    angular
     .module('exampleApp')
     .directive('myDirective', directive);

    function directive(){
        var ddo = {
            restrict: 'E',
            bindToController: true,
            controller: 'ExampleController',
            controllerAs: 'vm',
            link: linkFn,
            scope: {
                myValue: '@'
            },
            template: '<h1 ng-bind="vm.myValue"></h1><div class="directive-class"><button ng-click="vm.coolMethod()">It is Cool eh?</button><button ng-click="vm.anotherMethod()">Another</button></div>'
        }

        return ddo;

        function linkFn(scope, element, attrs, ctrl){
            console.log(scope.vm);
        }
    }


  })();

在HTML中

<div ng-app="exampleApp">
    <div ng-controller="ExampleController as example">
        <input ng-model="example.variableToDirective" />
        <my-directive my-value="10"></my-directive>
        <my-directive my-value="20"></my-directive>
    </div>
</div>

工作代码:http://goo.gl/B1WGtb