【问题标题】:How to get AngularJS to update the DOM on ng-repeat array splice? $scope.$apply() returns an error如何让 AngularJS 更新 ng-repeat 数组拼接上的 DOM? $scope.$apply() 返回错误
【发布时间】:2015-08-12 18:21:45
【问题描述】:

已解决 - 我有这个plunkr,它展示了我面临的问题。这是一个简单的图片上传器,它也使用FileReader 来显示图片(感谢angular-file-uploads)。我把它放在一个可以添加和删除的动态形式中。

问题:

  1. 在此plunkr 中,直到单击Add Another Image 后才会显示dataUrl。这可能是唯一的问题,因为 图像很好地显示在我的网站上。 --已解决

  2. 如果您将图像上传到第一个表单,然后单击Add Another Image,然后单击第一个选项卡,然后删除第一个选项卡,$scope.images 中的数据被删除但 DOM 没有更新。添加 $scope.$apply() 会导致摘要已在进行中错误。

  3. 上传输入显示旧文件名,但输入实际为空。

我的问题是:删除图像后如何更新 DOM?

更新:问题 #1 已解决,但问题 #2 和 #3 仍然存在。

更新2:我尝试为<input type="file" onchange="..." 附加$scope.$apply,但使用splice() 删除图像不会触发onchange 事件。

Update3:我添加了一个带有ng-model="image.caption" 的简单文本输入,以查看DOM 是否会适当更新。确实如此。如果images[0]images[1] 删除,DOM 也会正确更新。

Update4: Grundy 发现了问题:track by $index。删除它会使一切按预期工作。不完全确定为什么。

【问题讨论】:

  • 为什么在 ng-repeat 中使用 track by $index
  • 我使用track by $index 以便angular-file-uploads="{{ $index }}" 知道上传了哪个图像编号。我尝试删除track by $index,它似乎.......工作........而且,似乎 $index 无论如何都可以工作。我认为这解决了它!
  • @Grundy,我希望你能添加你的解释作为答案。
  • $indexngRepeat 中的特殊变量,它始终可用并且点头取决于您如何跟踪

标签: javascript angularjs dom angularjs-ng-repeat


【解决方案1】:

您的 ngRepeat
中的 track by 表达式存在问题 正如ngRepeat的文档中所说的那样

ngRepeat 对 DOM 进行相应的更改:

  • 添加项目时,模板的新实例会添加到 DOM。
  • 当一个项目被移除时,它的模板实例也会从 DOM 中移除。
  • 重新排序项目时,它们各自的模板在 DOM 中重新排序。

因此,在您拼接第一个元素的情况下,最后一个元素的 index 更改为 first 并且角度认为只需要从 DOM 中删除最后一个元素,而不需要先换吧。

另外,$index$last 等是 ngRepeat 范围内的特殊属性,因此它始终可用,不依赖于 跟踪表达式

【讨论】:

    【解决方案2】:

    好像image.dataUrl被缓存了什么的。

    添加

    ng-if="image.dataUrl"

    <img>标签

    似乎可以纠正这种情况,但它并没有解决根本问题..不管它是什么。

    【讨论】:

    • Grundy 暗示的问题是track by $index。删除它使其按预期工作。
    【解决方案3】:

    由于您的指令处理 AngularJs 中摘要循环之外的事件,因此您需要将任何更新包装到 scope.$apply() 中的范围内。所以在你的指令中:

     reader.onload = function() {
       var dataURL = reader.result;
       scope.$apply(function() {
         scope.$parent.upload(file, dataURL, attributes.angularFileUploads);
       });
     };
    

    【讨论】:

    • 而不是$scope.$apply,尝试注入$timeout 并执行$timeout(function () { /* stuff with $scope */ });
    • @StickyCube,我之前确实尝试过,但它没有改变任何东西。我为$timeout(function() {$scope.images.splice($scope.images.indexOf($scope.image), 1);}, 100);添加了$timeout
    猜你喜欢
    • 1970-01-01
    • 2015-01-18
    • 1970-01-01
    • 2016-02-12
    • 2014-10-11
    • 2014-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多