相当标准的情况。
有一个父组件<item-list>。在其模板内*ngFor生成了 20 个子组件<item-block>。[ngStyle]使用调用 function 的指令和模板表达式设置子组件样式setStyles()。
问题(或可能不是)是,当在一个特定子元素上发出任何事件时,表达式setStyles()会对每个子组件执行两次。
因此,如果我们单击示例中的一个特定项目,并且我们有 20 个<item-block>组件 -setStyles()将执行 20+20 次。
问题是:
示例&plnkr:
import {Component} from '@angular/core'
@Component({
selector: 'item-list',
template: `
<item-block
[item]="item"
*ngFor="let item of items"
></item-block>
`,
})
export class ItemListComponent {
items: any[] = [];
constructor() {}
ngOnInit() {
// generate dummy empty items
for (let i = …Run Code Online (Sandbox Code Playgroud) angular2-template angular2-changedetection angular2-components angular
我通过服务将对象数组共享给我的组件。因此,有一刻我想用新对象的属性替换数组对象的属性之一(我替换该对象)。因此,我的共享对象应该在使用它的所有模板中更新。
https://plnkr.co/edit/0sRxSivEaEPLsNAJo7MV?p=preview
// my.component.ts
@Component({
selector: 'my-component',
template: '<div>MyComponent: {{item.name}}</div>',
})
export class MyComponent implements OnInit {
constructor(private myService: MyService) {}
private item = myService.myListData[0];
ngOnInit() {
// 1. - This triggers change detection in app.ts template
this.item.name = 'Name 1111';
setTimeout(() => {
// 2. - This doesn't trigger change detection in app.ts template
let newObj = {name: 'Name 222', age: 225};
this.item = newObj;
}, 3000);
}
}
Run Code Online (Sandbox Code Playgroud)
在我的例子中 //1 更改 app.ts 和 my.component.ts 中的模板值,但 //2 仅在 my.component.ts …
假设我必须跟随实体
export class Photo {
public data: Blob;
public User: string;
}
Run Code Online (Sandbox Code Playgroud)
以下组件
@Component({
template: '<my-other-component [(ngModel)]="photo.data"></my-other-component>'
})
export class MyComponent {
@Input()
photo: Photo;
constructor(private photoService: PhotoService, private cd: ChangeDetectorRef){}
public deletePhoto(): void {
this.photoService.deletePhoto(this.photo)
.subscribe((result: ApiResult) => {
//if done here, change detection doesn't work
this.photo = new Photo();
});
//if done here, change detection works
this.photo = new Photo();
}
}
Run Code Online (Sandbox Code Playgroud)
PhotoService 是一个发出http 删除请求的服务。
my-other-component实施ControlValueAccessor
my-other-component每当我更改在方法中绑定到子组件的对象时subscribe,都不会传播任何更改。
如果我在我的方法之外调用它,subscribe它就会起作用并my-other-component收到有关更改的通知。
photo …
假设我有一个简单的文本数组:
textContent = [
{text: 'good morning'},
{text: 'lovely day'},
{text: 'for debugging'},
]
Run Code Online (Sandbox Code Playgroud)
我为每个组件渲染一个简单的组件,并传入文本项作为输入:
<app-text *ngFor="let text of textContent" [text]="text"></app-text>
Run Code Online (Sandbox Code Playgroud)
文本组件渲染文本,用ngModel:
<textarea [(ngModel)]="text.text"></textarea>
Run Code Online (Sandbox Code Playgroud)
我还登录了 DoCheck:
ngDoCheck() {
console.log(this.text.text, ' has been checked')
}
Run Code Online (Sandbox Code Playgroud)
当我在一个文本区域中输入某些内容时,所有其他组件的 DoCheck 都会被触发。
good morning has been checked
lovely days has been checked
for debuggings has been checked
Run Code Online (Sandbox Code Playgroud)
即使使用 OnPush 进行更改检测,也会发生这种情况。
问题:为什么对一个组件的数据进行更改会触发检查整个树?
(对于少数组件来说这不是问题,但是对于较大的树,我会丢帧)。
我实际上注意到,即使是完全独立的内容树上的组件也会触发其“doCheck”。
有没有办法防止这种情况发生,或者我完全错过了其他东西?
https://stackblitz.com/edit/angular-xpamld
问题:有人可以帮助我理解为什么我的原型changeDetection: ChangeDetectionStrategy.OnPush仍然允许我更新内部值name吗?如果这不是ChangeDetectionStrategy.OnPush应该阻止的,它应该做什么?
app.component.ts:
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent {
public name = 'Angular 5';
public changeName() {
this.name = 'Outer';
}
}
Run Code Online (Sandbox Code Playgroud)
app.component.html:
<hello name="{{ name }}"></hello>
<button (click)="changeName()">Outter Change</button>
<p>{{name}}-- outer</p>
<p>
Start editing to see some magic happen :)
</p>
Run Code Online (Sandbox Code Playgroud)
你好.component.ts:
@Component({
selector: 'hello',
template: `<h1>Hello {{name}}!</h1> <button (click)="changeName()">inner Change</button>`,
styles: [`h1 { font-family: Lato; }`],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export …Run Code Online (Sandbox Code Playgroud) 我正在阅读这篇文章,其中有一节介绍何时使用markForChange().
在他的示例中,他具有以下组件:
@Component({
selector: 'cart-badge',
template: '{{counter}}',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class CartBadgeComponent {
@Input() addItemStream;
counter = 0;
constructor(private cd: ChangeDetectorRef) {}
ngOnInit() {
this.addItemStream.subscribe(() => {
this.counter++;
this.cd.markForCheck();
});
}
}
Run Code Online (Sandbox Code Playgroud)
他使用该markForCheck()方法来更新视图。我不明白的是,为什么markForCheck()当调用detectChanges() 也更新视图时我们需要在这里使用?
我在 StackOverflow 上阅读了问题的答案 - MarkForCheck() 和 detectorChanges() 有什么区别?
但不符合上面的例子。那么,为什么不打电话detectChanges()呢markForCheck()?
使用OnPush变更检测来使变更灵活且在测试中也非常简单的最佳方法是什么?通过各种教程,我发现可以使用OnPush:
也许你知道不同的方法然后我列出的这个?
如何配置 Angular 组件不触发整个应用程序的更改检测,而只触发组件本身及其子组件?
工作示例:https : //stackblitz.com/edit/angular-irc-starter-4txpbu?file=app%2Ftimer%2Ftimer.component.ts
有一个计数器每秒增加一个值。它是 TimerComponent 并且它按预期工作 - 每秒增加和更新值。
@Component({
selector: 'app-timer',
template: `{{value}}`
})
export class TimerComponent implements OnInit {
value: number = 0;
ngOnInit() {
setInterval(() => this.value++, 1000);
}
}
Run Code Online (Sandbox Code Playgroud)
但是,请查看父组件 AppComponent。
<h3>Internal timer:</h3>
<p>Should not perform change detection for the whole app</p>
<app-timer></app-timer>
<h3>External binding</h3>
<p>Should not be updated after timer changes</p>
<p>{{someBindingProperty}}</p>
Run Code Online (Sandbox Code Playgroud)
someBindingProperty是一个吸气剂:
get someBindingProperty() {
this.bindingTimer++;
return this.bindingTimer;
}
Run Code Online (Sandbox Code Playgroud)
问题:当 TimerComponent 增加值时,会触发整个应用程序的更改检测。是否可以仅在组件和子组件内触发更改检测?
注意:如果我添加到 TimerComponent:
changeDetection: ChangeDetectionStrategy.OnPush
Run Code Online (Sandbox Code Playgroud)
然后在此组件中不会检测到更改,但仍会为整个应用程序触发更改检测。所以这不是一个解决方案。
我有带有对象数组的角度分量
export class AlertsConfigListComponent implements OnInit, DoCheck {
@Input() config: ProductAlertConfig[];
Run Code Online (Sandbox Code Playgroud)
并使用 IterableDiffer 来获取该数组的更改:
constructor(private iterableDiffers: IterableDiffers) {
this.iterableDiffer = iterableDiffers.find([]).create(null);
}
ngDoCheck(): void {
let changes : IterableChanges<ProductAlertConfig> = this.iterableDiffer.diff(this.config);
if (changes) {
this.doSmth();
}
Run Code Online (Sandbox Code Playgroud)
}
它有效,每次更改数组时我都可以得到更改。所以现在我的问题是。如何检查数组大小已更改的更改对象,因为当我对此数组进行排序时也会触发它。IterableChanges对象中没有用于此目的的属性。
如果我可以获得新的数组大小,我会这样做:
ngDoCheck(): void {
let changes : IterableChanges<ProductAlertConfig> = this.iterableDiffer.diff(this.config);
if (changes && newSize !== oldSize) {
this.doSmth();
}
Run Code Online (Sandbox Code Playgroud)
}
它可以解决问题,但是还有其他解决方案吗?
我正在尝试在 Angular 应用程序中切换到信号,目前在寻找良好实践方面遇到问题,并且我也经历了(至少对我来说)意外的行为。
这是我的代码片段,由一个 userService 和两个组件组成
export class UserService {
private user$: Observable<User>;
private refreshUser$ = new BehaviorSubject<void>(undefined);
constructor(private readonly http: HttpClient) {}
getUser(): Observable<User> {
if (!this.user$) {
this.user$ = this.refreshUser$.pipe(
switchMap(() => this.http.get<User>('...')),
shareReplay(1)
);
}
return this.user$;
}
reloadUser(): void {
this.refreshUser$.next();
}
}
Run Code Online (Sandbox Code Playgroud)
然后我有组件 A 为用户订阅:
export class aComponent {
currentUser: User;
constructor(private readonly userService: UserService) {
this.userService.getUser().subscribe((user) => {
this.currentUser = user;
});
}
}
Run Code Online (Sandbox Code Playgroud)
我有组件 aChild,它是组件 A 的子组件,也订阅用户并且还可以操作用户。它能够更改/删除用户的地址。在使用信号之前,我会立即更新组件的 currentUser 对象的地址,以便用户可以立即看到结果,并且我会从服务调用“reloadUser()”,以便全局用户是最新的,并且“A Component " 具有正确的值(这可能不是最好的解决方案,因为它会导致另一个 http …
rxjs angular2-changedetection angular angular-signals angular16