让我们想象我有一个包含一些数据的指令,我想在第二个组件(指令或其他)中将其插入其他地方,而不需要控制器链接它们。
例如,使用angularjs网页的zippy,但不是让<div ng-controller="Ctrl3">
将输入中的数据出价到 zippy指令,我们有两个单独的组件:
<!-- first component with data -->
<div ng-controller="aCtrl">
Title: <input ng-model="title"> <br>
Text: <textarea ng-model="text"></textarea>
</div>
<hr>
<!-- a second component wanting to show the data -->
<div class="zippy" zippy-title="Details: {{title}}...">{{text}}</div>
我的问题是如何在Angularjs中很好地链接它们?
我尝试通过服务,注册数据更改,然后尝试通过注入指令或通过控制器将其与我的DOM绑定失败。
(我想在另一个指令“window”中显示指令中包含的数据,但我不想用控制器包装我的所有代码只是为了绑定数据)
有没有办法很好地做到这一点?
答案 0 :(得分:0)
这是一个使用服务触发$rootScope
上的自定义事件的解决方案,然后在指令'
app.factory('SharedData',function($rootScope){
return{
data:{text : 'World', title:'Foo bar'},
upDate:function(prop,val){
this.data[prop]=val;
$rootScope.$emit('dataUpdate',prop)
}
}
});
app.controller('aCtrl', function ($scope,SharedData) {
angular.forEach(SharedData.data,function(value,key){
$scope[key] = value;
$scope.$watch(key,function(){
SharedData.upDate(key,$scope[key]);
});
});
});
app.directive('zippy',function($rootScope,SharedData){
return{
restrict:'C',
replace:false,
scope:{},
controller:function($scope) {
$rootScope.$on('dataUpdate',function(event,prop) {
$scope[prop] = SharedData.data[prop];
});
}
}
});
<强> Plunker Demo 强>
答案 1 :(得分:0)
除了将事件或包装指令发送到父控制器之外还有另一种选择(btw这些选项没有错)。另一个选择是拥有一个通用服务/工厂,您可以在其中注册任意指令控制器,然后在其他相关或非相关指令中使用这些注册控制器。
下面有一个名为directiveCommunicator
的服务,您可以在其中获取,设置和取消设置指令控制器(如果需要,可以使用工厂,只是我喜欢使用服务)。然后,我们有另外两个名为foo
和bar
的指令,foo
指令注册要使用的控制器,而bar
指令使用它们。请注意,foo
和bar
指令不是父/子相关的
// Service used to register/use any arbitrary controller
app.service('directiveCommunicator',
function()
{
var _controllers = {};
this.get =
function(id)
{
if (!(id in _controllers)) {
return null;
}
return _controllers[id];
};
this.set =
function(id, controller)
{
_controllers[id] = controller;
};
this.unset =
function(id)
{
if (!(id in _controllers)) {
return;
}
delete _controllers[i];
}
}
);
app.directive('foo',
[
'directiveCommunicator',
function(directiveCommunicator)
{
return {
'restrict': 'A',
'scope':
{
'colour': '='
},
'controller':
function($scope)
{
// We register out controller with a unique ID so we can use it in other directives
directiveCommunicator.set('colourBox', this);
// We also unregister it once we get destroyed, otherwise we'll be leaking memory
$scope.$on('$destroy',
function()
{
directiveCommunicator.unset('colourBox');
}
);
this.changeColour =
function(colour)
{
$scope.$apply(
function()
{
$scope._colour = colour;
}
);
}
},
'link':
function($scope, $element, $attr)
{
$scope._colour = $attr.colour;
$scope.$watch('_colour',
function()
{
$element.attr('class', $scope._colour);
}
);
}
}
}
]
);
app.directive('bar',
[
'directiveCommunicator',
function(directiveCommunicator)
{
return {
'restrict': 'A',
'scope':
{
'colour': '='
},
'link':
function($scope, $element, $attr)
{
$element.text($attr.colour);
$element.bind('click',
function()
{
// We get the registered controller and call the 'changeColour' method on it
var ctrl = directiveCommunicator.get('colourBox');
ctrl.changeColour($attr.colour);
}
);
}
}
}
]
);
我已经做了一些 Microsoft's source code 演示,看看foo
和bar
的实际效果。 foo
指令只是一个小方形div,您可以在其中更改关联控制器中的背景。 bar
是另一个非相关指令,它将调用foo
的控制器方法changeColour
并根据提供的属性更改颜色。
Haven尚未在生产中使用此设置,您还需要处理取消注册的控制器,但应该可以正常工作。您还可以在directiveCommunicator.set
方法中将第3个参数作为控制器的范围,该方法将自动添加到$ destroy / unregister设置中,因此不必再调用directiveCommunicator.unset