首页 > 解决方案 > 更新列表时,Angular *ngFor 不响应

问题描述

当我更新父组件中的列表时,我无法在子组件中获得反应性。

我拥有的数据非常嵌套,看起来像这样

{ //projectList
  "projects": [
        {
            "name": "project",
            "displayed":true,
            "layers": [
                {
                    "name": "child_1",
                    "displayed":true
                    "layers": [
                        {
                            "name": "child_1_1",
                            "displayed":true
                        },
                        {
                            "name": "child_1_2",
                            "displayed":true

                        }
                    ]
                }
            ]
        }
    ]
}

在父组件中,我像这样使用 *ngFor:

 <li *ngFor="let project of projectList">
                <child1
                    *ngIf="project.displayed"
                    [project]="project"
                ></child1>
  </li>

child1 组件还使用另一个 child2 以便在结构包含更多层时更深入地了解结构。所以 child2 组件使用递归来创建更多级别,但我认为问题发生在此之前。

我在这里要做的是过滤列表并在父组件的嵌套结构中设置 display:false 。我希望 child1 和 child2 检测到此更改,为什么不发生?

(显示的例子被简化了很多)

触发更改检测的一种解决方案是在我更改显示的属性后执行 projectList = copy(projectList) ,但这会引入一些不需要的行为

过滤器功能(简化了很多):

  private setfilteredProjectList() { //STARTS HERE
        this.projectList?.forEach((projectArray) => {
            projectArray.layers.forEach((layer) => {
                    let filterSearch = this.filterSearchString(layer);
                    layer = filterSearch.layer;
                          
            });
        });
    }

 private filterSearchString(layer: Layer) {
        if (!layer.layers?.length) {
            if (this.search === '') {
                layer.displayed = true;
            } else {
                if (
                    layer.layername
                        .toLowerCase()
                        .startsWith(this.search.toLowerCase())
                ) {
                    layer.displayed = true;
                } else {
                    layer.displayed = false;
                }
            }
        } else {
            layer.layers.map((l) => {
                let childFiltered = this.filterSearchString(l);
                return childFiltered.layer;
            });
        }
        return { layer };
    }

更新:我看到我犯了一个很大的错误;在 setfilteredProjectList() 中使用 forEach 代替 map ...

标签: angular

解决方案


这是reference类型(数组和对象)的问题,我们必须更改 RAM 的位置以确保发生更改检测,当您有嵌套的对象和数组时,它会变得麻烦和烦人,但试试这个。

private setfilteredProjectList() { //STARTS HERE
       // assign projectList to a new array
        this.projectList = this.projectList?.map(project => { // the map in both cases 
            const layers = project.layers.map(layer => {     // creates a new location in
               let filterSearch = this.filterSearchString(layer); // memory and ensures
               return filterSearch.layer;                         // change detection 
            });                                                   // to take place
            return {
              ...project, // spread the old project object
              layers,     // update the layers value
            };
        });
    }

推荐阅读