In my attempts at having angularjs and d3js working together smoothly, I run in trouble when I try to watch an attribute value right within a directive. Let me illustrate with those two simple directives:
在我试图让angularjs和d3js顺利协同工作时,当我尝试在指令中查看属性值时,我遇到了麻烦。让我用这两个简单的指令来说明:
.directive('attr1', function($compile) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var attr3val = 0;
d3.select(element[0])
.attr('attr2', true)
.attr('attr3', attr3val)
.on('click', function() {
d3.select(element[0])
.attr('attr3', function() {
attr3val++;
console.log("new attr3 value is", attr3val);
return attr3val;
});
});
element.removeAttr("attr1");
$compile(element)(scope);
}
};
})
.directive('attr2', function() {
return {
restrict: 'A',
scope: {
attr3: "=attr3"
},
link: function(scope, element, attrs) {
scope.$watch('attr3', function() {
console.log('attr3 modification trigger');
});
}
};
});
They are shown in action here - console logs have to be activated to understand clearly what happens.
它们在此处显示 - 必须激活控制台日志才能清楚地了解发生的情况。
Following this thread, I use $compile
so that the attr2
directive is effectively bound after the DOM is modified by d3 calls. I then would like to watch the changes of another attribute (attr3
here). Using a private scope in attr2
, I thought this to be possible, but I must be doing something wrong, as clicks in the blue square do indeed update the attribute value, but without the watch being triggered.
在这个线程之后,我使用$ compile,以便在d3调用修改DOM之后有效地绑定attr2指令。然后我想看另一个属性的变化(这里是attr3)。在attr2中使用私有作用域,我认为这是可能的,但我必须做错了,因为蓝色方块中的点击确实更新了属性值,但没有触发监视。
Maybe DOM attributes are not "watchable"? Are the only viable solutions those prescribed here?
也许DOM属性不是“可观看的”?这是唯一可行的解决方案吗?
Thanks by advance for your keen help!
感谢您提前寻求帮助!
EDIT
The solution using $broadcast
shown hereunder is working strictly speaking, but is ineffective if the attribute is common to many elements, and I want to watch one specifically. I'm thus going for a $watch
on a function evaluation that uses jQuery, as shown here.
使用下面显示的$ broadcast的解决方案严格来说,但如果该属性对于许多元素是通用的,则无效,我想特别注意一个。因此,我要在使用jQuery的函数评估中观察,如此处所示。
2 个解决方案
#1
1
If you want to $watch an attribute, you can use $observe:
如果你想$ watch一个属性,你可以使用$ observe:
link: function(scope, element, attrs) {
attrs.$observe('attr3', function(newValue) {
console.log('attr3 is ', newValue);
});
}
#2
1
One way to solve this problem is to create custom scope events via $broadcast()
within your directives and then attach a listener to the receiving directive.
解决此问题的一种方法是在指令中通过$ broadcast()创建自定义范围事件,然后将侦听器附加到接收指令。
PLUNKER
e.g.
例如
.directive('attr1', function($compile) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var attr3val = 0;
d3.select(element[0])
.attr('attr2', true)
.attr('attr3', attr3val++)
.on('click', function() {
d3.select(element[0])
.attr('attr3', attr3val++);
scope.$broadcast('attr3-change', attr3val);
});
element.removeAttr("attr1");
$compile(element)(scope);
scope.$broadcast('attr3-change', attr3val);
}
};
})
.directive('attr2', function() {
return {
restrict: 'A',
link: function(scope, element, attrs) {
scope.$on('attr3-change', function(event, args) {
console.log(args);
})
}
};
});
#1
1
If you want to $watch an attribute, you can use $observe:
如果你想$ watch一个属性,你可以使用$ observe:
link: function(scope, element, attrs) {
attrs.$observe('attr3', function(newValue) {
console.log('attr3 is ', newValue);
});
}
#2
1
One way to solve this problem is to create custom scope events via $broadcast()
within your directives and then attach a listener to the receiving directive.
解决此问题的一种方法是在指令中通过$ broadcast()创建自定义范围事件,然后将侦听器附加到接收指令。
PLUNKER
e.g.
例如
.directive('attr1', function($compile) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var attr3val = 0;
d3.select(element[0])
.attr('attr2', true)
.attr('attr3', attr3val++)
.on('click', function() {
d3.select(element[0])
.attr('attr3', attr3val++);
scope.$broadcast('attr3-change', attr3val);
});
element.removeAttr("attr1");
$compile(element)(scope);
scope.$broadcast('attr3-change', attr3val);
}
};
})
.directive('attr2', function() {
return {
restrict: 'A',
link: function(scope, element, attrs) {
scope.$on('attr3-change', function(event, args) {
console.log(args);
})
}
};
});