AngularJS ng-if 在 $compile 后不删除元素

AngularJS ng-if not deleting element after $compile

我有一个执行以下操作的指令:

  1. 向元素添加另一个指令属性。
  2. 删除自己的属性。
  3. 在元素上调用 $compile() 使 AngularJS 重新编译元素以便附加新指令。

这很好用,除非我还向元素添加了 ng-if。请参阅这个最小示例并按照以下步骤进行演示。

https://embed.plnkr.co/ymk0RwGopGF1KvesWmvA/

  1. + 任意次数添加到 "count"。
  2. 0重置"count"。
  3. 再次按 + 任意次数。

我希望 "my-test shown" <p> 标记从 DOM 中删除,一旦它的 ng-if 条件在步骤 #2 后不再为真。相反,它会保留下来,您会在步骤 #3 后看到该消息的额外副本。

我假设在 my-test 指令 link 函数中调用 $compile($element)($scope); 会产生一些意想不到的后果,但我不明白这里发生了什么。有什么想法吗?

谢谢, 大卫

我不知道如何正确解释,但 ng-if 为元素添加了一个新的范围,他自己的范围,检查这个问题以查看更多详细信息:what is the difference between ng-if and ng-show/ng-hide。我试过 ng-show 并且它按照你想要的方式工作:

ng-show="count > 0"

希望对您有所帮助=)

据我所知,当您将 count 的值更改为 0 时,您的指令会在更改 count 的值之前被销毁。所以未删除的指令的计数值仍然是 1.

如果你使用ngShow而不是ngIf,你可以解决这个问题。因为 ngShow 属性不会触发 $destroy 事件,也不会从您的视图中删除元素。因此该指令可以捕获 count 的新值。或者您可以使用 prelink 而不是 link 来捕获 count 值的更新。

正如其他人回答的那样,简短的解决方案是使用 ng-show 而不是 ng-if 或不使用 $compile 那样。除此之外,您可能有充分的理由为什么要像这样使用 ng-if$compile

这个问题让我对使用 $compileng-if 的隔离范围感兴趣。我用 this fork 做了一些试验,并将尝试解释我的发现。

我们已经知道 ng-if 创建了一个隔离范围,但是随后通过 $compile 传递带有 ng-if 的元素创建 另一个 隔离作用域(并且会使新编译的 ng-if 在第一轮隔离作用域中查看变量——指令的 $scope 值)。

重申一下,我们有一些范围看起来像([] 中的值是范围。$id):

  1. main/outer 控制器有 scope[2]

  2. ng-if my-test 元素有 ng-if 查看 scope[2].count 并创建 scope[3]

  3. my-test 链接器因此有 $scope.$id == 3;

  4. my-test 执行 $compile - 重新编译 ng-if 元素:创建新的隔离 scope[4] 并查看 scope[3].count

  5. scope[2].count 命中 0 - scope[3] 得到 $destroyed(因为 scope[3] 是由第一个 ng-if 创建的,它仍然是在某处徘徊)......但是!元素是 A. 仍然存在并且 B. 它的计数没有更新 - 为什么?

好吧,因为仍然存在的元素是 $compiled 并且有 A. 一个 ng-if 查看 scope[3].count(现在 $destroyed)和 B. 它的自己的新隔离 scope[4](通过重新编译 ng-if 元素与父元素 scope[3] 创建)

所以你。这一切都非常令人困惑,您可能只是想问...我该如何解决这个问题?

TL;DR;

最简单的解决方案: $element.removeAttr('ng-if'); 在你做 $compile($element)($scope);

之前

如果您一直在关注,这会起作用,因为原始 ng-if 仍在查看 scope[2].count,并且存在的元素不再获得第二个隔离范围。