所有
如何将当前DOM元素传递给Angular指令" ng-disabled"?
我知道在Angular中弄乱DOM是不好的做法。但我无法想到另一种 - 简单 - 这样做的方法。这是我的问题:
我有一个按钮,在点击时更新范围变量:
<button ng-click="target_model.display_detail=true">click me</button>
在我的模板的其他地方,有一些代码可以监视&#34; target_model.display_detail&#34; - 当它为真时,它会显示一个模态对话框,其中包含一个Angular指令,该指令从服务器获取一些数据并填充表单,其中包含另一个按钮,如上面的。
我正在使用的数据结构可能是递归的;有大量的嵌套&#34; target_models&#34;。因此,模态对话框中的按钮可以指向其形式已经创建的target_model。在这种情况下,我只想禁用该按钮。我喜欢这样的东西:
<button ng-disabled="ancestor_model_exists(the_current_element, target_model.some_unique_id)">click me</button>
其中&#34; ancestor_model_exists&#34;是一个函数,它将检查DOM以查看是否存在具有特定id的祖先元素。但是我怎么知道从哪个元素开始呢?
答案 0 :(得分:1)
你正在迫切地接近DOM操作 - jQuery方式,而不是声明方式 - Angular方式。
DOM操作很好......内部指令。你不能在控制器中做到这一点,你可能会定义这个功能。
如果有机会,请尝试在沙箱中拨打0 $
电话,迫使您学习如何以Angular的方式做事 - 而不是因为它更好&&#34;更好& #34;绝对的方式 - 无论如何,在你按照自己的方式进行之前,首先要学习工具包和推荐的方法通常会更好。
这应该做你想要的,除了可能搜索超过多个祖先(但我提到如果你需要的话如何做):
https://plnkr.co/edit/7O8UDuqsVTlH8r2GoxQu?p=preview
<强> JS 强>
app.directive('ancestorId', function() {
return {
restrict: 'A',
controller: 'AncestorIdController',
require: ['ancestorId'],
link: function(scope, element, attrs, controllers) {
var ancestorIdController = controllers[0];
// If you wanted to use an expression instead of an
// interpolation you could define an isolate scope on this
// directive and $watch it.
attrs.$observe('ancestorId', function(value) {
ancestorIdController.setId(value);
});
}
}
});
app.controller('AncestorIdController', function() {
this.getId = _getId;
this.setId = _setId;
var id;
function _getId() {
return id;
}
function _setId(value) {
id = value;
}
});
app.directive('disableForAncestorId', function() {
return {
restrict: 'A',
require: ['?^ancestorId'],
link: function(scope, element, attrs, controllers) {
var ancestorIdController = controllers[0];
// Check to make sure the ancestorId is a parent.
if (ancestorIdController) {
scope.$watch(function() {
var watch = {
target: ancestorIdController.getId(),
actual: attrs.disableForAncestorId
};
return watch;
}, function(value) {
if (value.target === value.actual) {
element.attr('disabled', 'disabled');
} else {
element.removeAttr('disabled');
}
}, true /* Deep watch */ );
}
}
}
});
<强> HTML 强>
<!-- The simple happy path. -->
<div ancestor-id="A">
<button disable-for-ancestor-id="A">'A' === 'A' ?</button>
</div>
<!-- require will match the 'B' before the 'A' because it's closer.
if you need to match any parent you could use a third coordinating
directive. -->
<div ancestor-id="A">
<div ancestor-id="B">
<button disable-for-ancestor-id="A">'B' === 'A' ?</button>
</div>
</div>
<!-- require lets you freely change the DOM to add extra elements separating
you from what you're looking for.-->
<div ancestor-id="B">
<div>
<div>
<button disable-for-ancestor-id="B">'B' === 'B' ?</button>
</div>
</div>
</div>
<!-- It doesn't blow up if it doesn't find an ancestorId. -->
<div>
<button disable-for-ancestor-id="B">'B' === undefined ?</button>
</div>
<br>
Dynamic AncestorId test (it will be disabled if the text fields are equal):
<br>
Target AncestorId <input ng-model="targetAncestorId">
<br>
Actual Ancestor <input ng-model="actualAncestorId">
<!-- It doesn't blow up if it doesn't find an ancestorId. -->
<div ancestor-id="{{ targetAncestorId }}">
<button disable-for-ancestor-id="{{ actualAncestorId }}">'{{ actualAncestorId }}' === '{{ actualAncestorId }}' ?</button>
</div>
答案 1 :(得分:0)
它永远不会失败...在Stack Overflow上发布一个问题总能让我在几分钟后意识到答案。
以下代码让我非常接近:
<强> template.html:强>
<button ng-click="display_if_ancestor_model_exists($event, target_model)">click me</button>
<强> app.js:强>
$scope.display_if_ancestor_model_exists = function($event, target_model) {
var ancestor_form = $($event.target).closest("#" + target_model.some_unique_id);
if (ancestor_form.length) {
/* don't show the modal-dialog */
display_msg("This form already exists!");
}
else {
target_model.display_detail = true;
}
};
当然,我宁愿禁用该按钮,但我现在可以使用此解决方案。