我有一个图表指令:
.directive('chart', function() {
return {
...
controller: function($scope) {
this.toggleAnimation = function() {
...
};
},
link: function link(scope, element, attrs) {
...
}
}
});
我正在使用它:
<div ng-controller='foo'>
<chart></chart>
</div>
foo
的位置:
.controller('foo', function($scope) {
// TODO: call chart's toggleAnimation
});
现在,如何从toggleAnimation
控制器中调用chart
指令上的foo
函数?
或者这不是设置应该如何?我在这里要做的是为我的chart
指令创建一个函数,允许任何消耗它的函数将指令中的变量转换为true / false。
答案 0 :(得分:1)
.directive('chart', function() {
return {
scope: {
toggle: "@" // pass as string - one way // you could also make this an attr if you want
},
...
controller: function($scope) {
},
link: function link(scope, element, attrs) {
...
var toggleAnimation = function() {
...
};
// when you change this value, it will toggle the animation
// logic which will check the values of this variable so you can do if statements and modify animations
scope.$watch('toggle', function(newVal, oldVal){
console.log(newVal);
if(parseInt(newVal) === 1)
toggleAnimation();
else if(parseInt(newVal) === 0)
; // do something else like toggle back
});
}
}
});
HTML
<div ng-controller='foo'>
<chart toggle="myVariable"></chart>
</div>
Controller JS
.controller('foo', function($scope) {
// TODO: call chart's toggleAnimation
$scope.myVariable = 0; // initialize to this value
function clickSomething(){
$scope.myVariable = 1; // change, hence fire animation
}
});
答案 1 :(得分:1)
有两种主要机制可以使数据在特定指令或控制器之间流动。数据可以使用范围和表达式向下范围层次结构(通常镜像DOM树),也可以使用指令控制器API以向上层次结构。这两种机制都需要一个指令与另一个特定指令进行通信。
第三种沟通机制是范围事件。这个机制是关于一个与零或更多其他指令/控制器进行通信的指令,它并不是必须知道的。
使用哪种机制取决于具体方案。以下部分概述了每个部分,然后概述了每个部分的权衡。 (在您给出的具体示例中,我使用了第一个,但您似乎对一般机制感兴趣,而不仅仅是您的具体示例。)
将数据向下传递树的惯用方法是提供图表访问其父作用域的数据。在这种情况下,它会像这样使用:
<div ng-controller="Foo">
<chart animated="chartAnimated"></chart>
</div>
上面的chartAnimated
是控制器插入的范围变量。以下是Foo
控制器中的外观:
.controller('Foo', function($scope) {
$scope.chartAnimated = true;
$scope.toggleAnimation = function () {
$scope.chartAnimated = ! $scope.chartAnimated;
};
});
图表指令然后需要支持这个新属性,这可以使用指令声明中的scope
属性来实现:
.directive('chart', function() {
return {
scope: {
// This requests that Angular parse the expression in the 'animated'
// attribute and write a function for it into the scope as
// 'animationEnabled'.
'animationEnabled': '&animated'
},
link: function link(scope, iElement, attrs) {
// Now we can watch the expression to detect when it changes.
scope.$watch(
scope.animationEnabled,
function (isEnabled) {
// This function will be called once on instantiation and then
// again each time the value of the expression changes.
// Use ``isEnabled`` in here to either enable or disable animation.
console.log('Animation', isEnabled ? 'is enabled' : 'is disabled');
}
);
}
}
});
虽然它并不适用于您给出的示例,但我们还要探索我提到的其他数据流技术,其中数据流 up 树。
在这种情况下,父指令可以将API公开给子指令。例如,ngModel
指令与其父form
指令的交互方式,或ngSwitchWhen
与其父ngSwitch
的交互方式。
这里的关键是指令声明中的require
属性,它允许指令依赖于当前元素或某个父元素上的另一个指令。为了这个例子,我们将在任何父元素上查找它。
让我们做一个父母指令的一个人为设想的例子,它有许多孩子,由于某些原因需要跟踪:
<parent>
<child name="foo"></child>
<child name="bar"></child>
<child name="baz"></child>
</parent>
我们首先定义parent
指令:
.directive('parent', function() {
return {
controller: function () {
this.children = {};
this.registerChild(name, child) {
console.log('Got registration for child', name);
this.children[name] = child;
}
}
}
});
child
指令是我们可以使用require
机制的地方:
.directive('child', function() {
return {
require: '^parent', // Must be nested inside a 'parent' directive
link: function (scope, iElement, attrs, parentCtrl) {
// Notice the extra 'parentCtrl' parameter above.
// Provide an API for parent to interact with child.
var child = {};
child.doSomething = function () {
console.log('Child', attrs.name, 'requested to do something');
};
parentCtrl.registerChild(attrs.name, child);
}
}
});
在这种情况下,我们在父级和子级之间建立双向通信通道,子级使用require
启动通道,并将父级与子级通信的对象传递给父级。当使用require
时,link
会有一个额外的参数,为控制器提供所请求的指令。
最后,让我们谈谈事件。这些最适用于您有一个指令(或者实际上,拥有范围的任何其他代码)希望向正在收听的人广播特定通知的情况。例如,$route
使用ng-view
事件与$routeChangeSuccess
(以及正在侦听的其他任何人)进行通信,ng-view
通过$viewContentLoaded
警告应用程序的其余部分scope.$on
。
事件观察者属于范围,事件在范围层次结构中上下传播。
如果您持有示波器,则可以使用scope.$on(
'$viewContentLoaded',
function () {
console.log('view content loaded!');
}
);
监视可能通过的任何事件:
$emit
如果您要发送一个事件,您可以使用scope.$emit(
'somethingHappened'
);
向范围层次结构发送消息 :
$broadcast
...或者您可以使用scope.$broadcast(
'somethingHappened'
);
向范围层次结构发送向下消息:
$broadcast
在某些情况下,您希望将事件传递给整个应用程序,在这种情况下,您可以$rootScope
上的$rootScope.$broadcast(
'somethingHappened'
);
:
require
要记住事件的一个重要事项是它们是一个点对多点&#34;机制,也就是说许多不同的接收者可能会看到&#34;同样的消息。这使得事件成为两个特定参与者之间定向交流的相当差的机制,因此应该谨慎使用事件。
因此,概述了AngularJS中指令的三种数据流机制。每种方法都有不同的权衡:
ngSwitch
机制最适合用于提供需要多个强相关元素参与的模板构造,例如在ngSwitchWhen
仅存在ngSwitch
的情况下使用{{1}},没有它就毫无用处。答案 2 :(得分:0)
您可以使用$scope.$broadcast
向指令中的子范围广播事件。该指令将监听该指令,然后在听到正确的事件时运行该方法:
$scope.$broadcast("toggleAnimation", this.textToBroadcast);
小提琴: