从另一个模块访问范围的指令
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 () {
//✅ : ✖
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 = "✅"
}).error(function (data, status, headers, config) {
$scope.validation.message = data;
$scope.validation.success = false;
$scope.validation.symbol = "✖"
});
}
}]);
关于我在这里做错了什么还有其他见解吗?
我也尝试过这种格式的指令,因为我认为这是处理指令范围的首选方式,结果没有任何变化。
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 + " " + " ✅");
element.children("span").css("color", "green");
}
else {
element.children("span").html($scope.validationmessage + " " + " ✖");
element.children("span").css("color", "red");
}
}
}, true);
}
};
});
您应该尝试使指令自包含,而不是直接访问父范围,然后监视要对更改做出反应的表达式。
angular.module("myApp").directive("myappmessage", function () {
//✅ : ✖
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>
(这些控制器,顺便说一句,可以很容易地来自不同的模块)
所以,我是 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 () {
//✅ : ✖
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 = "✅"
}).error(function (data, status, headers, config) {
$scope.validation.message = data;
$scope.validation.success = false;
$scope.validation.symbol = "✖"
});
}
}]);
关于我在这里做错了什么还有其他见解吗?
我也尝试过这种格式的指令,因为我认为这是处理指令范围的首选方式,结果没有任何变化。
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 + " " + " ✅");
element.children("span").css("color", "green");
}
else {
element.children("span").html($scope.validationmessage + " " + " ✖");
element.children("span").css("color", "red");
}
}
}, true);
}
};
});
您应该尝试使指令自包含,而不是直接访问父范围,然后监视要对更改做出反应的表达式。
angular.module("myApp").directive("myappmessage", function () {
//✅ : ✖
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>
(这些控制器,顺便说一句,可以很容易地来自不同的模块)