2017-10-08 60 views
0

我有一个组件层次结构,看起来有点像这样:角2个变化探测阵列

@Component({ 
... 
}) 
export class A { 

    constructor(private _serviceThatDeliversData: Service){} 

    getData(): Array<DataItem> { 
    return this._serviceThatDeliversData.getData(); 
    } 
} 

HTML:

<b-selector [data]="getData()"></b-selector> 

子组件:

@Component({ 
    selector: 'b-selector' 
    ... 
}) 
export class B { 
    @Input() data: Array<DataItem>; 
} 

HTML:

<ul> 
    <li *ngFor="let item of data"> 
    <c-selector [item]="item"></c-selector> 
    </li> 
</ul> 

所以我得到了一个从服务接收数据的父组件'A'。 serviceThatDeliversData每次从WebSocket接收数据时都会创建DataItem列表。然后将这个列表传递给'B',其中每个列表条目都被用作子组件的基础('C',这里我省略了C组件,因为它基本上只呈现输入数据'项目')。

我现在的问题如下: 由于每次服务获取更新时列表都会更改,因此C组件的所有列表+ B组件都是新创建的。我假设,因为DataItem列表完全改变Angular通知他们作为新的条目(?)和列表作为一个新的本身(?) 但实际上很可能是只有一个项目被添加或删除或只是一个字段在其中一个项目中更改。所以只需要删除/添加/更新一个C组件。

既然是这样,任何C组件中的视图中发生的任何动画都会在重新创建列表后停止并重新开始。这加上我想避免的一些其他副作用。

所以我的问题是,有没有办法让Angular只更新与实际内部改变的DataItem相关的C组件,以及添加到列表中或从列表中移除的那些组件,没有改变没有改变?

我搜索了一段时间,发现可以使用changeDetection:ChangeDetectionStrategy.OnPush,但是我还没有找到一个工作示例(具有更改数组和更改数组元素(内部)),这将帮助我解决问题。

我假设可以在'B'中存储列表副本,手动检查更改,然后对它们做出反应 - 也可以通过动画向用户发出信号,告知用户哪些条目已被删除或添加 - 但是,将需要一种方法来阻止Angular更新(重新创建)'B'和'C'组件。我使用相同的数组(清除它并用新条目重新填充它)可能会起作用。

但我仍然想知道这是否可以通过原始的Angular机制来实现。

+1

看到[这个答案](https://stackoverflow.com/questions/45940888/how-to-prevent-calling-constructor-of-component-in-ngfor-directive/45942413#45942413) –

回答

1

更改检测策略OnPush只会修改由Input-deccorator修饰的值,并且只有在值的引用发生更改时才会发生更改。

例如myArray[1] = 'a';只会改变数组,并且不会创建新的参考,因此,使用OnPush策略的角度不会引起更改。您必须克隆数组并进行更改以创建新的数组引用。

你的角度重新创建ngForOf指令中的元素的问题在我的另一个answer中描述。在答案结尾阅读注释。

+0

但不是每次服务更新时都会重新创建数组本身,这是一个问题吗?那不会被认为是一个变化吗?列表元素将全部重新创建,因为列表本身已经改变了?链接的答案在ngFor循环中重用组件的方式看起来很有希望。但我认为,我必须在所有字段上提供某种散列,以便trackby允许更新实际需要更改的C组件。另外:如果新组件与被删除的组件具有相同的“身份”,会发生什么情况? –

+0

您可以简单地按照答案中的描述返回'trackBy'函数内的索引。数据仍然会更新,但角度不会重新创建DOM元素,这会阻止对它们进行动画。因此,只有当一个项目被添加或从列表中移除时,该元素的动画才会被调用。 – cyrix