从另一个模块访问范围的指令

Directives Accessing Scope From Another Module

所以,我是 AngularJS 的新手,我可能没有正确地解决这个问题,尤其是在我使用指令的方式上。

我有一个主应用程序,我想在其中放置一些通用代码,例如在 html 页面上显示一些消息的指令。我有一个控制器进行休息 API 调用以验证凭据,然后将一些数据分配给 $scope。我希望指令使用该范围数据在 html 中显示消息并进行一些格式化。根据我的研究,从控制器执行此操作并不是最佳做法。我知道我可以直接在控制器中执行此操作,只需将 div 放在 html 中,例如:

<div>{{validation.message}}</div>

html的简化版本是:

    <html data-ng-app="myApp" data-ng-strict-di>
        <body>
            <div data-ng-view data-ng-controller="MainController">
                <div data-ng-app="StoredAccountsModule" data-ng-controller="AccountController">
                    <button class="btn btn-default" data-ng-click="modalOptions.verify(newAccount)">Verify Credentials</button>
                    <div data-myappmessage></div>
                </div>
            </div>
        </body>
    </html>

指令是:

angular.module("myApp").directive("myappmessage", function () {
    //&#9989 : &#10006
    return {
        link: function postLink(scope, element, attrs) {

            element.html('<span>' + scope.validation.message + '</span>');
    }
    };
});

我确定我遗漏了一些关于控制器、模块和指令如何连接在一起的信息。

更新

好的,根据大家的评论,我已经解决了我正在尝试做的事情中的很多问题。现在,我正在尝试通过单击按钮从 bootstrap 模态启动帐户验证,该按钮会启动对 return 验证信息的 API 调用。模态正在作为服务启动,如下所示:http://weblogs.asp.net/dwahlin/building-an-angularjs-modal-service。重要的模态 window 部分是:

<div data-ng-controller="MainController">
    <div data-simplevalidation></div>
</div>
<div class="modal-footer">
    <button class="btn btn-primary" data-ng-click="modalOptions.ok(newAccount)">{{modalOptions.actionButtonText}}</button>
    <button class="btn btn-warning" data-ng-click="modalOptions.close('cancel')">{{modalOptions.closeButtonText}}</button>
    <button data-ng-controller="MainController" class="btn btn-default" data-ng-click="verifyAccount(newAccount)">Verify Credentials</button>
</div>

模态正在从以下位置启动:

<div data-ng-controller="StoredAccountsIndexController" style="width:auto;text-align:center;">
    <table style="border:1px solid black;margin:auto;">
        <tfoot>
            <tr>
                <td colspan="2"><button type="button" class="btn btn-primary" data-ng-click="open()">Add New Stored Account</button></td>
            </tr>
        </tfoot>
    </table>
</div>

指令现在是

angular.module("myApp").directive("simplevalidation", function () {
    return {
        template: '<button type="button" class="btn btn-default" data-ng-click=verifyAccount(newAccount)>Verify</button><span></span>',
        link: function ($scope, element, attrs) {
            $scope.$watchGroup(["validation.message", "validation.success"], function () {

                if ($scope.validation.success != null) {
                    if ($scope.validation.success) {
                        element.children("span").html($scope.validation.message + " " + $scope.validation.symbol);
                        element.children("span").css("color", "green")
                    }
                    else {
                        element.children("span").html($scope.validation.message + " " + $scope.validation.symbol);
                        element.children("span").css("color", "red")
                    }
                }

            }, true);
        }
    };
});

页面上只声明了一个应用程序,myApp。我相信我遇到的问题与模态的范围有关。如果我使用指令模板放置的按钮,一切都会按预期方式进行。如果我使用模式页脚中的按钮,API 调用会触发,但我从未在我的范围内看到更新。处理该调用的控制器是:

angular.module("myApp").controller("MainController", ['$scope', '$timeout', "StoredAccountsFactory", function ($scope, $timeout, StoredAccountsFactory) {
    $scope.validation = {}

    $scope.verifyAccount = function (account) {
        $scope.validation = {};

        StoredAccountsFactory.validateStoredAccount(account).success(function (data, status, headers, config) {
            $scope.validation.message = "Account credentials verified";
            $scope.validation.success = true;
            $scope.validation.symbol = "&#9989;"
        }).error(function (data, status, headers, config) {
            $scope.validation.message = data;
            $scope.validation.success = false;
            $scope.validation.symbol = "&#10006;"
        });
    }
}]);

关于我在这里做错了什么还有其他见解吗?

我也尝试过这种格式的指令,因为我认为这是处理指令范围的首选方式,结果没有任何变化。

angular.module("myApp").directive("simplevalidation", function () {
    //add these attributes to the directive element
    //data-validate="verifyAccount(newAccount)" data-validationmessage="validation.message" data-validationsuccess="validation.success"

    return {
        scope: {
            validate: '&',
            validationmessage: '=',
            validationsuccess: '='
        },
        template: '<button type="button" data-ng-click=validate()>Verify</button><span></span>',
        link: function ($scope, element, attrs) {
            $scope.$watchGroup(["validationmessage", "validationsuccess"], function () {

                if ($scope.validationsuccess != null) {
                    if ($scope.validationsuccess) {
                        element.children("span").html($scope.validationmessage + " " + " &#9989;");
                        element.children("span").css("color", "green");
                    }
                    else {
                        element.children("span").html($scope.validationmessage + " " + " &#10006;");
                        element.children("span").css("color", "red");
                    }
                }

            }, true);
    }

    };
});

您应该尝试使指令自包含,而不是直接访问父范围,然后监视要对更改做出反应的表达式。

    angular.module("myApp").directive("myappmessage", function () {
        //&#9989 : &#10006
        return {
            scope: { 
              message: '='
            },
            link: function postLink(scope, element, attrs) {                            
                scope.$watch('message', function(value) {
                    element.html('<span>' + value + '</span>');
                });
            }
        };
   });

然后按如下方式使用:

<div data-myappmessage message="validation.messages"></div>

你误解了这里的一些概念,我认为它使你试图做的事情过于复杂。

1.模块: 模块只是一种使用依赖关系组织代码的方式。加载后,哪个模块承载哪个 service/controller/directive.

并不重要

2。应用和 ng-app: 每个页面确实应该有一个应用程序。您 可以 有多个,但您需要手动 angular.bootstrap 它们,而且我很确定它们不能嵌套。此外,应用程序不共享相同的服务实例或范围,因此应用程序实际上是一个独立的执行单元(从 Angular 的角度来看)。

因此,StoredAccountsModule 应用与 myApp 的嵌套应该不会发生:

<html ng-app="myApp" >
  <body>
     <div data-ng-view data-ng-controller="MainController">
        <div data-ng-app="StoredAccountsModule">
           ...
        </div>
     </div>
  </body>
</html>

3。控制器:

控制器定义和设置视图模型(通过 $scope 或使用控制器作为方法)。你发表的声明:

I know I could do this directly in the controller and just put a div in the html like:

<div>{{validation.message}}</div>

暗示它违反最佳实践(而不是创建指令)显然是错误的。

不鼓励(并且不赞成)在控制器中操作、访问或以其他方式对视图(即 DOM)做出任何假设。那是因为控制器只处理后端模型和视图模型之间的数据转换和编组。

换句话说,控制器处理应用程序的体系结构和逻辑 - 而不是它在视图中的表现形式。

控制器和依赖注入 (DI) 的特性使控制器具有高度可测试性。

4.指令: 指令意味着(在大多数情况下)是直接处理 DOM 的可重用功能。指令不应(理想情况下)围绕 HTML 或控制器做出任何假设。

Angular 确实允许指令使用外部范围,但它使它们更少 re-usable。在这方面,您的指令 myappmessage 没有提供太多价值。

即使在编写指令时,也不应忘记 Angular 支持的 MVVM 原则。因此,指令也有一个作用域和一个控制器,并且可以重用其他指令和 built-in 指令来实现其功能。

5.范围: 范围独立于模块或控制器或指令。所以这个问题的标题“accessing scope from another module”是没有意义的。 Angular 为应用程序创建根范围。

控制器和指令共享作用域(除非指令创建隔离作用域),因此 parent 控制器将变量发布到作用域上,通过作用域继承使其子树可以使用该变量。

作用域继承只是控制器之间通信的一种方式(有些人认为这是一种不好的做法),但它存在并且可以使用(如果使用得当,考虑到作用域的原型继承性质的所有约束)。

app.controller("ParentCtrl", function($scope){
   var VM = $scope.VM = ($scope.VM || {});

   VM.isBusy = false;
})
.controller("ChildCtrl", function($scope, $http){
   var VM = $scope.VM = ($scope.VM || {});

   $scope.loadSomething = function(){
      VM.isBusy = true;
      $http.get("something").then(function(d){
         VM.isBusy = false;
      });
   }
});

在视图中:

<div ng-controller="ParentCtrl">
  <div ng-show="VM.isBusy">loading...</div>
  <div ng-controller="ChildCtrl">
    <button ng-click="loadSomething()">load</button>
  </div>
</div>

(这些控制器,顺便说一句,可以很容易地来自不同的模块)