Angular 从Typescript获取程序初始化输入数组时,在新对象上迭代时,角度材质按钮不可单击
我有以下令人困惑的角度问题 编辑:我设法在Stackblitz示例中重现了这一点,并更新了此处的文本。 以闪电战为例 这显示了四组三个列表项,带有删除图标,并具有以下配对:Angular 从Typescript获取程序初始化输入数组时,在新对象上迭代时,角度材质按钮不可单击,angular,angular-material,Angular,Angular Material,我有以下令人困惑的角度问题 编辑:我设法在Stackblitz示例中重现了这一点,并更新了此处的文本。 以闪电战为例 这显示了四组三个列表项,带有删除图标,并具有以下配对: string input/passed from a getter string input/passed from a field array input/passed from a getter array input/passed from a field 在array/getter案例中当我单击第一个(从项目1)时
string input/passed from a getter
string input/passed from a field
array input/passed from a getter
array input/passed from a field
在array/getter案例中当我单击第一个(从项目1
)时,控制台中没有任何记录;但是单击第二个(来自items2
)或第三个(来自items3
),它会记录“删除”
。在其他情况下,它总是按照预期记录delete
这里可能发生了什么事?
代码如下,尽管很容易使用
首先是父HTML,它设置了四种情况:
带getter的字符串
不带getter的字符串
带getter的数组
无getter的数组
和打字稿:
@组件({
选择器:“我的应用程序”,
templateUrl:“./app.component.html”,
样式URL:['./app.component.css']
})
导出类AppComponent{
获取名称1():字符串{
返回“角度”;
}
名称2=‘角度’;
获取名称1():字符串[]{
返回['Angular'];
}
名称2=['Angular'];
}
然后是组件HTML:
一些文本
删除
一些文本
删除
一些文本
删除
和打字稿:
@组件({
选择器:“你好”,
templateUrl:“./hello.component.html”,
样式:[`h1{font-family:Lato;}`]
})
导出类HelloComponent{
@Input()名称:string;
@Input()名称:字符串[];
项目1:编号[]=[];
项目2:编号[]=[];
项目3=[新编号(42)];
ngOnChanges(){
this.items1=[新编号(42)];
this.items2=[42];
}
删除(){
console.log('delete');
}
}
在hello.component.ts
中,如果您更改this.items1=[新编号(42)]
tothis.items1=[42]代码>
它正在工作
老实说,我无法确切地告诉您原因,但它是有效的:-)似乎与使用常规类型编号
有关,可能与ngochanges()
中Angular的ChangeDetection结合使用。我个人知道这些类型存在,但从未见过有人使用它们。
关于这一点,我在网上读到:
永远不要使用数字、字符串、布尔值或对象类型。这些类型指的是在JavaScript代码中几乎从未正确使用过的非基本装箱对象
这意味着您最好使用小写字母,如number
来指定类型,而不要使用构造函数来创建新的number
s
我希望这有帮助 这里的一个问题(虽然不是根本原因)是,当使用ngFor
循环时,Angular使用对象标识跟踪是否需要重新渲染。有关讨论,请参阅。因此(见下文)添加一个trackBy
函数可以解决这个问题
在糟糕的情况下:
- 将getter与列表一起用于输入会导致使用相同的值调用两次
ngOnChanges
。Angular可能会访问输入两次(我不知道为什么),但每次访问时,getter都会返回一个新列表,该列表具有不同的标识,因此ngOnChanges
会被调用两次
- 它不会被
字符串getter调用两次;字符串
对象是相同的
- 调用
ngOnChanges
时,它会重置坏列表(items1
)以包含新对象
结果是,在本例中,Angular渲染列表两次,因为它认为所有元素从一个过程更改为下一个过程
现在:我不知道为什么这会导致按钮无法点击。但是Angular允许您覆盖trackBy
函数,该函数用于确定列表中的元素是否已更改。将其更改为按索引跟踪(此处不更改)可以解决问题
Forked Stackblitz解决了这个问题,它增加了:
到组件的Typescript:
trackByIndex(索引,项){
收益指数;
}
在HTML循环中:
一些文本
删除
你本质上是。。。某种程度上。。。创建递归
通过将输入传递到触发器ngochanges
,从而初始化*ngFor
的值李>
然后更新视图,因为初始值为空
然后,当视图“更改”并更改基础标识时,它会触发另一个ngOnChanges
事件李>
等等。。。等等
正如您指出的,在每次迭代中,“身份”都会发生变化
迭代器中元素的标识可以在
数据不存在。*例如,如果迭代器是
从RPC生成到服务器,并重新运行该*RPC。即使
数据没有更改,第二个响应生成具有*
不同的身份和角度必须破坏整个DOM和
重建它(就好像所有旧*元素都被删除,所有新元素都被删除一样
插入的元素)
用setTimeout
将ngOnChanges
中的块包装起来,并在其前面放置一个console.log
,这将暴露我试图说明的潜在问题并破坏堆栈
- 我知道这是一个非常激烈的例子来说明这里正在发生的事情,但我认为重要的是要把它发挥到极致,以了解你正在尝试的方法正在发生什么
ngOnChanges() {
console.log('test')
//setTimeout(()=>{
// this.items1 = [new Number(42)];
// this.items2 = [42];
// })
}
ngAfterViewInit(){
//passing the input to the *ngFor or figuring out some other way to update the
`hello.component` array would be a more stable solution. Leveraging `ngOnChanges`
to modify the view via component variable will not be a stable approach.
for (const name in this.names) {
this.items1 = [new Number(42)];
this.items2 = [42];
}
}
刚刚在一个本地项目中尝试了你的代码,对我来说效果不错。只是一个随机猜测:可能是你的CSS导致了这种行为。是