【问题标题】:How to bind to controller vars from sibling directives如何从兄弟指令绑定到控制器变量
【发布时间】:2015-05-13 09:42:57
【问题描述】:

我试图弄清楚 AngularJS 是如何工作的(或应该如何工作)。我想到了一个非常简单的应用程序,它带有页眉、主要内容和页脚。主要内容有一个 mainCtrl 保存大部分数据(此阶段没有服务)。我在主要内容 div 之外构建了页眉和页脚作为指令。是否可以(或推荐)从我的指令中访问和更改(绑定)mainCtrl 变量?我阅读了控制器和控制器,创建了控制器的副本,而 require 可能是我想要的。但我无法让它工作。也许一些信息和指向正确的方向可能会有所帮助。 PS让每个控制器使用服务/工厂获取数据会更好吗?如果是的话,在控制器中存储一些数据而不是一直调用服务不是很有效吗? 如果您需要任何说明,请告诉我。

*编辑:此处演示:plunker Demo

<!DOCTYPE html>

<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>My AngularJS App</title>
    <meta name="description" content="">
    <link rel="stylesheet" href="bower_components/angular-material/angular-material.css">
    <link rel="stylesheet" href="app.css">
</head>
<body ng-app="menuApp">
<div header-directive></div>
<hr/>
<div style="min-height: calc(100vh - 400px)" ng-controller="MainController as main">

    <p>Direct access to (mainCtrl) SCOPE user: {{ user }}</p>
   <p>Direct access to mainCtrl user: {{ main.user }}</p>

<ul>
    <li ng-repeat="item in main.menuItems"><a ng-href="#/{{ item.toLowerCase() }}">{{ item }}</a></li>
</ul>
<!--<img src="http://ost2.gr/files/gimgs/1_random2.png">-->
<ng-view></ng-view>
</div>

<div footer-directive></div>

Below footer: {{ main.user }}

<script src="bower_components/angular/angular.js"></script>
<script src="bower_components/angular-animate/angular-animate.js"></script>
<script src="bower_components/angular-material/angular-material.js"></script>
<script src="bower_components/angular-aria/angular-aria.js"></script>
<script src="bower_components/angular-route/angular-route.js"></script>
<script src="app.js"></script>
<script src="menuApp.config.js"></script>
<script src="mainController.js"></script>
<script src="ProductsController.js"></script>
<script src="ChartsController.js"></script>
<script src="AboutController.js"></script>
<script src="footerDirective.js"></script>
<script src="headerDirective.js"></script>
</body>
</html>   

主控制器:

(function () {
    'use strict';

    angular
        .module('menuApp')
        .controller('MainController', MainController);

    MainController.$inject = ['$scope'];

    /* @ngInject */
    function MainController($scope) {
        /* jshint validthis: true */
        var vm = this;

        vm.activate = activate;
        vm.title = 'main';

        activate();

        ////////////////

        function activate() {
            vm.menuItems = ['Main', 'Products', 'Charts', 'About'];
            $scope.user = 'SCOPE USER';
            vm.user = 'user from MainController';
        }
    }
})();

头指令:

  (function () {
        'use strict';

        angular
            .module('menuApp')
            .directive('headerDirective', headerDirective);

        headerDirective.$inject = ['$window'];

        /* @ngInject */
        function headerDirective($window) {
            // Usage:
            // 
            // Creates:
            // 
            var directive = {
                //link: link,
                restrict: 'EA', //This means that it will be used as an attribute and NOT as an element. I don't like creating custom HTML elements
                replace: true,
                templateUrl: "header.html"
                //require: '^MainController'
                //scope: { user: '=' }
                ,controller: 'MainController'
                ,controllerAs: 'main'
            };
            return directive;

            //function link(scope, element, attrs) {
            //}
        }
    })();

页脚指令:

(function () {
    'use strict';

    angular
        .module('menuApp')
        .directive('footerDirective', footerDirective);

    footerDirective.$inject = ['$window'];

    /* @ngInject */
    function footerDirective($window) {
        // Usage:
        // 
        // Creates:
        // 
        var directive = {
            //link: link,
            restrict: 'EA',
            replace: true,
            templateUrl: 'footer.html',
            require: "^headerDirective"
            //scope: {'main.user': '='}, // This is one of the cool things :). Will be explained in post.
            //,controller: 'MainController'
            //,controllerAs: 'main'
        };
        return directive;

        //function link(scope, element, attrs) {
        //}
    }
})();

页眉模板:

<div>

    <p>Scope user: {{ user }} </p>

    <p>Main user: {{ main.user }}</p>
    <hr/>

    <p>
        This part of the header is always here
    </p>

    <p ng-if="user">
        User is logged in :D
    </p>

    <p ng-if="!user">
        Hey buddy, log in! Be cool
    </p>
    <hr/>

    <p>Scope user: <input ng-model="user"> {{ user }}</p>

    <p>Main user: <input ng-model="main.user"> {{ main.user }}</p>

</div>

页脚模板:

<md-toolbar class="md-medium-tall">
    <div layout="row" layout-align="center center" flex>
        <span>FOOTER</span>
    </div>
    $SCOPE USER: {{ user }}
    <hr/>
    MAIN USER: {{ main.user }}
</md-toolbar>

【问题讨论】:

  • 您能否为您的实际应用程序提供一个 plunker ?无论如何,我觉得您想要做的是配置指令的隔离范围。查看隔离范围部分的docs.angularjs.org/guide/directive

标签: angularjs angularjs-directive


【解决方案1】:

如果您的指令位于控制器 div 之外,那么无论您如何配置指令范围,您都无法访问控制器的范围。

您可以使用服务并将服务注入到 MainCtrl 和指令中,或者您的用例的一个好的做法是放置一个将成为应用程序全局范围的 Parent 控制器。然后将指令范围配置为从父控制器继承

例如

<div ng-controller="ParentCtrl">
  <div header-directive></div>
  <div ng-controller="ChildCtrl">
  </div>
  <div footer-directive></div>
</div>

【讨论】:

  • 我想到的是一个大应用程序。它可能有 5-6 个选项卡和一个根据所选选项卡更改的主要内容区域。他们中的一些或全部可能希望访问相同的数据以读取或更改它。我通常试图在没有 $scope 变量的情况下工作。是否有可能或建议我有许多指令,每个指令都有自己的模板但同一个控制器绑定到它们?以便他们可以访问和更改与该控制器相关的值? (我知道保留 vars 等不是控制器的工作,但我正在努力了解全局)
  • 我不喜欢将同一个控制器附加到多个指令的想法。指令应该是独立的组件。所以我将把所有的全局数据放在父控制器中,就像我的例子中一样
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多