【问题标题】:ngRepeat error when removing child directive from parent directive从父指令中删除子指令时出现 ngRepeat 错误
【发布时间】:2016-10-30 06:02:39
【问题描述】:

我在使用图库管理器组件时遇到了一些问题,您可以在其中添加/删除图片。

这是画廊处理程序的 html 代码:

<img src = '{{snapshot}}' >
<div class = 'md-button l3' is-file ng-model = 'picture' blob-url = 'snapshot'>Upload</div>
<div class = 'md-button l3' ng-click = 'article.pictures.push(picture)'>Add</div>   

<div gallery-manager = 'article.pictures'></div>

下面是指令:

.directive("galleryManager", function($compile){
        var controllerFn = function($scope, $element, $attrs){
            var self = this;        
            self.removeItemAt = function($index){
                self.pictures.splice($index, 1);
                $compile($element)($scope); <--Note this
            }
        }
        var linkFn = function($scope, $element, $attrs){
        }

        return {
            template:"<div gallery-item = 'picture' ng-repeat = 'picture in galleryManagerCtrl.pictures track by $index'></div>",
            restrict:"A",   
            controller:controllerFn,
            controllerAs:"galleryManagerCtrl",
            bindToController:{
                pictures:"=galleryManager",
            }
        }
    })
    .directive("galleryItem", function(FileService){
        var linkFn = function($scope, $element, $attrs, galleryManagerCtrl){
            $scope.galleryItemCtrl.galleryManagerCtrl = galleryManagerCtrl;
        }
        var controllerFn = function($scope, $element, $attrs){
            var self = this;
            if ( self.item instanceof File ){
                FileService.buildBlobUrl(self.item).then(function(blobUrl){
                    self.thumb = blobUrl;
                })
            }
        }
        return{
            template:"<img src = '{{galleryItemCtrl.thumb}}'>"+
                "<a class = 'delete' ng-click = 'galleryItemCtrl.galleryManagerCtrl.removeItemAt($index)'>&times</span></a>",
            restrict:"A",
            require:"^galleryManager",
            link:linkFn,
            controller:controllerFn,
            bindToController:{
                item:"=galleryItem",
            },
            controllerAs:"galleryItemCtrl"
        }
    })

目前,该指令在添加元素时运行良好,但在删除项目时出现问题;使用之前: $compile($element)($scope) 删除后,在图库中,总是消失最后一个项目,虽然图片数组删除了正确的项目,所以我在删除一个项目后添加了 $compile 行。

问题是,虽然画廊现在做了我想做的事,但它在编译后一直抛出错误(发布完整的跟踪,也许它可以帮助某人):

angular.js:13920 TypeError: Cannot read property 'insertBefore' of null
    at after (http://localhost/www/project/admin/bower_components/angular/angular.js:3644:13)
    at JQLite.(anonymous function) [as after] (http://localhost/www/project/admin/bower_components/angular/angular.js:3728:17)
    at domInsert (http://localhost/www/project/admin/bower_components/angular/angular.js:5282:35)
    at Object.move (http://localhost/www/project/admin/bower_components/angular/angular.js:5488:9)
    at ngRepeatAction (http://localhost/www/project/admin/bower_components/angular/angular.js:29865:26)
    at $watchCollectionAction (http://localhost/www/project/admin/bower_components/angular/angular.js:17385:13)
    at Scope.$digest (http://localhost/www/project/admin/bower_components/angular/angular.js:17524:23)
    at ChildScope.$apply (http://localhost/www/project/admin/bower_components/angular/angular.js:17790:24)
    at HTMLAnchorElement.<anonymous> (http://localhost/www/project/admin/bower_components/angular/angular.js:25890:23)
    at defaultHandlerWrapper (http://localhost/www/project/admin/bower_components/angular/angular.js:3497:11)

这似乎来自 ngRepeatDirective 的 watchCollection。

我觉得我错过了一些基本的东西,但看不到现在是什么,所以,在深入研究 Angular 代码之前,我来问一下。

提前谢谢你。

编辑

添加了一个工作示例: http://codepen.io/sergio0983/pen/rMEMoJ?editors=1010

编辑 2

从工作示例中删除了 $compile,它可以工作,是的,但会引发错误;此外,我认为真正的问题在别处。在工作示例中,您可以看到删除项目时文件名如何更新,但图片仍保持原始顺序。

【问题讨论】:

  • 不应该使用$compileng-repeat 手表将为您改变视图
  • 如果我不使用编译,总是删除最后一张照片(嗯,不是真的:模型是正确的,但视图总是删除 lastPicture);我将尝试制作代码示例
  • 索引可能不正确,最好在控制器中进行自己的索引,而不是依赖$index ...尤其是在使用任何过滤器时
  • 有同样的感觉,但没有找到更快的方法来获得这个。无论如何,我可以删除 $index,但我认为这不会解决问题。

标签: angularjs


【解决方案1】:
  1. addPicture() 函数添加到您的mainController(这将为图片对象添加恒定的唯一ID):

    .controller("mainController", function($scope){
      $scope.article = {pictures:[]};
      $scope.addPicture = function addPicture (picture) {
        // set unique ID
        picture.id = $scope.article.pictures.length;
        $scope.article.pictures.push(picture);
      };
    })
    
  2. 将添加按钮 HTML 更改为:

    <div class='md-button l3' ng-click='addPicture(picture)'>Add</div>
    
  3. galleryManagertemplate 更改为 track by picture.id:

    <div gallery-item='picture' 
         ng-repeat='picture in galleryManagerCtrl.pictures track by picture.id'></div>
    
  4. 修改removeItemAt()函数,(这里不需要$compile):

    self.removeItemAt = function removeItemAt (id) {
      // find index for the picture with given id
      id = self.pictures.findIndex((item) => item.id === id);
      self.pictures.splice(id, 1);
    }
    

    修改后的codepen:http://codepen.io/anon/pen/mrZOre?editors=1010

【讨论】:

  • 似乎可行,我会在部署后立即将其标记为已接受的答案(现在无法测试)。首先要检查向文件对象添加字段是否有副作用,并且应该在指令的控制器内分配 id。
猜你喜欢
  • 1970-01-01
  • 2013-11-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-28
  • 1970-01-01
相关资源
最近更新 更多