我有想法将输入包装到自定义指令中,以保证整个网站的外观和行为一致.我还想包装bootstrap ui的datepicker和dropdown.此外,该指令应处理验证和显示工具提示.
HTML应该看起来像这样:
要么
在指令中我想创建一个dom结构,如:
..//display validation in here..//add button to toggle datepicker (or other stuff) in here..//add input field in here
我尝试了各种方法来实现这一目标,但总是遇到一些权衡:
使用transclude和replace将输入插入到指令dom结构中(在这种情况下,指令将被限制为'A'而非'E',如上例所示).这里的问题是,没有简单的方法来访问transcluded元素,因为我想在datepicker的情况下添加自定义属性.我可以使用transclude函数,然后在链接函数中重新编译模板,但这对于此任务来说似乎有点复杂.这也会导致transcluded范围和datepicker的切换状态出现问题(一个在指令范围内,另一个在transcluded范围内).
仅使用替换.在这种情况下,所有属性都应用于最外层的div(即使我在编译函数中生成模板dom结构).如果我只使用输入作为模板,那么属性在输入上,但我需要在链接函数中生成模板然后重新编译它.据我所知,角度的相位模型,我想避免重新编译和更改链接函数中的模板dom(虽然我看到很多人这样做).
目前我正在使用第二种方法并在链接功能中生成模板,但我想知道是否有人有更好的想法!
以下是我认为正确的方法.像OP一样,我希望能够使用属性指令来包装input
.但我也希望它可以与之合作,ng-if
而不会泄漏任何元素.正如@jantimon指出的那样,如果你不清理你的包装元素,它们会在ng-if之后停留,如果它会破坏原始元素.
app.directive("checkboxWrapper", [function() { return { restrict: "A", link: function(scope, element, attrs, ctrl, transclude) { var wrapper = angular.element('<div class="wrapper">This input is wrappered</div>'); element.after(wrapper); wrapper.prepend(element); scope.$on("$destroy", function() { wrapper.after(element); wrapper.remove(); }); } }; } ]);
而且这里有一个plunker你可以玩.
重要提示:scope
vs element
$ destroy.你必须把你的清理放入scope.$on("$destroy")
而不是element.on("$destroy")
(这是我最初尝试的).如果你在后者(元素)中执行它,那么"ngIf end"注释标记将被泄露.这是由于Angular的ngIf在它做出错误逻辑时如何清理其结束注释标记.通过将指令的清理代码放在范围$ destroy中,您可以将DOM放回原来,就像它在输入之前一样,因此ng-if的清理代码很高兴.到调用element.on("$ destroy")时,在ng-if falsey流程中打开原始元素而不导致注释标记泄漏为时已晚.