执行/渲染来自另一个指令的指令
execute/render a directive from another directive
我有以下两个指令。在DirectiveA
中,我从远程服务器获得一些数据,然后将该数据渲染为anchor
标签的模板。现在,当用户点击任何链接,我broadcast
事件,并听取该事件在DirectiveB
。在DirectiveB我想使另一个ajax请求,当我收到响应的数据,然后我要呈现DirectiveB
模板。我目前的方法不起作用,因为它在开始时执行两个指令,当时我没有DirectiveB
的任何数据。下面是代码
DirectiveA
angular.module('app').directive('DirectiveA', function ($http) {
'use strict';
return {
restrict: 'E',
templateUrl: '/templates/templateA.html',
controller: function ($scope) {
$scope.showDetails = function (num) { // <-- this executes in ng-click in template
$scope.$broadcast('season', num);
};
},
link: function (scope, element, attributes) {
$http.get(attributes.resource).then(function (response) {
scope.rows = response.data;
scope.seasons = [];
for (var i = 0; i < scope.rows.length; i++) {
var num = parseInt(scope.rows[i].data);
if (year >= 2005 && year <= 2015) {
scope.seasons.push({ 'data': scope.rows[i].data });
}
}
});
}
};
});
这是DirectiveB
angular.module('app').directive('DirectiveB', function() {
return {
restrict: 'E',
templateUrl: 'templates/templateB.html',
controller: function($scope, $http) {
$scope.$on('season', function ($scope, num) { // I listen to that event
$http.get('http://demo.com/api/' + num).then(function (response) {
$scope.standings = response.data;
});
});
}
};
});
以下是我在HTML 中使用它的方法
<directive-a resource="http://demo.com/api/>
</directive-a>
<directive-b></directive-b>
我还在等待它的解决方案
更新3
templateA
<ul>
<li ng-repeat="row in seasons">
<a href="#" ng-click="showDetails(row.season)">{{ row.season }}</a>
</li>
</ul>
模板B <h3>Standings</h3>
<table>
<thead>
<th ng-repeat="standing in standings" ng-if="state">{{ position }}</th>
</thead>
<tbody>
<tr ng-repeat="row in standings">
{{ row.Driver }}
</tr>
</tbody>
</table>
你的问题归结为:
-
如何保证
DirectiveA
和DirectiveB
之间的通信由于您的两个指令使用相同的作用域,您的解决方案与事件广播工作。一旦您将DDO中的
scope
设置更改为false
以外的任何其他设置,这种情况就会中断。这就是为什么我建议你在
$rootScope
上$broadcast
事件 -
一旦数据准备好,如何渲染
DirectiveB
的模板一个简单的
ngIf
封装指令的模板就可以完成这项工作。我们不需要任何花哨的东西
Bellow是一个简单的工作示例。注意这两个指令是如何使用隔离作用域的——这只是为了展示为什么需要$rootScope.$broadcast
。我还使用$timeout
来模拟服务器的延迟。
angular
.module('myApp', [])
.directive('directiveA', function() {
return {
templateUrl: 'tempA.html',
controller: function($rootScope, $scope) {
$scope.sendMessage = function(message) {
$rootScope.$broadcast('eventName', message);
};
},
scope: {}
};
})
.directive('directiveB', function() {
return {
templateUrl: 'tempB.html',
controller: function($rootScope, $scope, $timeout) {
$scope.messages = [];
$rootScope.$on('eventName', function(event, message) {
$timeout(function() {
$scope.messages.push(message);
}, 50);
});
},
scope: {}
};
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js"></script>
<div ng-app="myApp">
<directive-a></directive-a>
<directive-b></directive-b>
<script type="text/ng-template" id="tempA.html">
<h2>Hello from DirectiveA</h2>
<label>
<p>Message to send to DirectiveB</p>
<input type="text" ng-model="toSend">
</label>
<button type="button" ng-click="sendMessage(toSend); toSend = '';">Send</button>
</script>
<script type="text/ng-template" id="tempB.html">
<div ng-if="messages.length > 0">
<h3>Hello from DirectiveB</h3>
<ul>
<li ng-repeat="message in messages track by $index">{{ message }}</li>
</ul>
</div>
</script>
</div>
使用API (angular服务)在你的指令之间进行通信。在我的例子中,我称之为MyAPIService:
angular.module('app').service('MyAPIService', function () {
this.display = false;
this.seasons = [];
});
然后在指令和指令A中注入你的API实例,当你点击锚点时,你必须填充你的季节并更新你的"display"变量。在你的指令下,只需观察"display"变量
angular.module('app').directive('DirectiveA', function ($http, MyAPIService) {
'use strict';
return {
restrict: 'E',
templateUrl: '/templates/templateA.html',
controller: function ($scope) {
$scope.showDetails = function () {
MyAPIService.display = true;
},
link: function (scope, element, attributes) {
$http.get(attributes.resource).then(function (response) {
scope.rows = response.data;
MyAPIService.seasons = [];
for (var i = 0; i < scope.rows.length; i++) {
var num = parseInt(scope.rows[i].data);
if (year >= 2005 && year <= 2015) {
MyAPIService.seasons.push({ 'data': scope.rows[i].data });
}
}
});
}
};
});
angular.module('app').directive('DirectiveB', function() {
return {
restrict: 'E',
templateUrl: 'templates/templateB.html',
controller: function($scope, $http, MyAPIService) {
// WATCH "DISPLAY" VARIABLE AND CALL YOUR AJAX
}
};
});
我有一个工作的解决方案给你,有点不同于你的广播方法。正如你所提到的,你希望在点击指令a之后才加载指令B的数据。所以,我们将添加一个条件来从DOM中删除指令B。当点击指令A触发时,我们将使指令B加载到DOM中。这样你的指令B的控制器将在稍后的时间点被加载。
下面是支持我的参数 的代码指令angular.module('app').directive('DirectiveA', function ($http) {
'use strict';
return {
restrict: 'E',
templateUrl: '/templates/templateA.html',
controller: function ($scope) {
$scope.showDetails = function (num) { // <-- this executes in ng-click in template
$scope.isDirectiveBVisible = true;
};
},
link: function (scope, element, attributes) {
$http.get(attributes.resource).then(function (response) {
scope.rows = response.data;
scope.seasons = [];
for (var i = 0; i < scope.rows.length; i++) {
var num = parseInt(scope.rows[i].data);
if (year >= 2005 && year <= 2015) {
scope.seasons.push({ 'data': scope.rows[i].data });
}
}
});
}
};
});
B指令angular.module('app').directive('DirectiveB', function() {
return {
restrict: 'E',
templateUrl: 'templates/templateB.html',
controller: function($scope, $http) {
$http.get('http://demo.com/api/' + num).then(function (response) {
$scope.data = response.data;
});
}
};
});
HTML <directive-a resource="http://demo.com/api/>
</directive-a>
<directive-b ng-if="isDirectiveBVisible"></directive-b>
很久以前,我创建了这个解决方案,就像实验
<div ng-directive="{{directive}}"></div>
可以动态渲染指令。
但是你的问题不是关于动态渲染的。是关于改变组件(指令)的状态。
你已经提供了关于使用ngIf
的答案,这个东西只在放它的地方。我建议把它放在你的指令中,并为整个模板制作包装器:
<div ng-if="isShown">
<h3>Standings</h3>
...
</div>
并在需要的地方设置isShown
scope属性,例如在事件之后:
$scope.$on('season', function ($scope, num) {
$scope.isShown = true;
});
或ajax调用后:
$http.get('http://demo.com/api/' + num).then(function (response) {
$scope.isShown = true;
});
此外,我建议不仅要使用可见性,还要使用加载指示来显示它正在加载:
<div ng-if="isShown">
<loading-indicator ng-if="isLoading">
<div ng-if="!isLoading">
<h3>Standings</h3>
...
</div>
</div>
您可以尝试在指令A中使用ng-if和某种标志来指示ajax请求已经完成。Ng-if将隐藏的元素包装在注释中,这样在条件为真之前,它们就不会出现在dom中。
From "AngularJs $scope documentation"
向所有子作用域(及其子作用域)分配一个事件名,通知已注册的$rootScope。听众范围。
这意味着你的directiveB必须是你的directiveA的子级才能捕捉到广播事件。例如:
<directive-A>
<directive-B></directive-B>
</directive-A>
指令的控制器的函数代码将在html渲染之前执行,而链接的函数代码将在html渲染之后执行。这意味着您不能处理directiveB的执行。当您有指令a中调用的响应时,您可以简单地创建它。例如:
scope.data={resolved:false};
$http.get(attributes.resource).then(function (response) {
scope.rows = response.data;
scope.seasons = [];
scope.data.resolved = true;
for (var i = 0; i < scope.rows.length; i++) {
var num = parseInt(scope.rows[i].data);
if (year >= 2005 && year <= 2015) {
scope.seasons.push({ 'data': scope.rows[i].data });
}
}
});
在上面的HTML示例中:
<directive-A>
<directive-B ng-if="data.resolved"></directive-B>
</directive-A>
通过这种方式,当您的调用被解决时,您的directiveB将被创建。
注意:如果你使用ngIf,你可能会丢失$broadcast事件,因为你的directiveB的$on会在$broadcast
我认为最好的解决方案,如果你想保留两个指令,是在你的指令B模板中使用ng-if
指令,只在有结果时显示表。
你只需要修改你的指令B模板来添加一个条件到你的当前表,并添加一个<div>
或类似的,当用户还没有选择任何项目时显示消息。
你的指令B模板应该是:
<h3>Standings</h3>
<!-- Add ng-if here -->
<table ng-if="standings.length > 0">
<thead>
<th ng-repeat="standing in standings" ng-if="state">{{ position }}</th>
</thead>
<tbody>
<tr ng-repeat="row in standings">
{{ row.Driver }}
</tr>
</tbody>
</table>
<!-- and also here -->
<!-- If standings is not an array -->
<div ng-if="!standings.length">
<p>Please, select one of the items above to show standings.</p>
</div>
您可以根据需要添加任意多的带有条件的div。例如,当所选项目没有结果时,您可以添加一条消息:
<!-- If standings is an array but it is empty -->
<div ng-if="standings.length && standings.length > 0">
<p>There are no standings to show.</p>
</div>
- 如何在另一个组件中获取指令/组件实例
- 如何使用其他自定义指令中的元素标记作为另一个自定义指令的模板
- 调用另一个自定义指令的角度自定义指令
- AngularJs 从指令中的另一个调用控制器
- 如果指令包含在另一个指令中,我如何在隔离范围内添加双向数据绑定属性
- 测试依赖于另一个指令Angularjs的指令
- 如何在angularjs中访问一个指令作用域值到另一个指令
- 当uib分页被包装在另一个指令中时,AngularJS表数据没有更新
- ng-repeat=“(key, value)” 不能将 {{key}} 的值用作另一个指令的全局范围的一部分
- 如何在angularjs中将一个具有赋值的指令转换为另一个指令
- 从另一个模块访问作用域的指令
- 从另一个指令访问指令的作用域变量
- 如何从另一个指令访问指令的 DOM 元素
- 如何仅当存在时才要求指令(在另一个指令内)
- 使用 AngularJS 需要选项调用另一个指令
- 另一个排除指令内的角度排除指令
- 使用一个指令从另一个独立作用域复制范围属性
- 角度:在另一个模态指令中加载的谷歌地图指令保持空白
- 自定义指令如何知道它是否已单击另一个控件
- 在另一个指令中使用 ui-tinymce 指令