从这两个帖子:
我了解在"更改检测"发生时DOM是如何更新的.我从"你需要了解的关于Angular中的变化检测的所有内容"中不了解的是Angular如何跟踪函数内部使用的属性,以及何时运行"更改检测".
我们假设这是父组件视图.
<child [prop]="func()"></child>
Run Code Online (Sandbox Code Playgroud)
这里func()是
func() { return this.parentProp }
Run Code Online (Sandbox Code Playgroud)
并且parentProp尚未在模板中使用.如果parentProp服务改变了,Angular如何知道func()依赖于什么parentProp,因此应该触发"更改检测"并更新视图.
我只需要在加载组件或路由发生变化时检测一次角度变化,然后我想停止检测变化。
实际上我需要根据用户角色显示和隐藏功能。所以我*ngIf在一个 html 模板中有很多,但是我只需要在*ngIf第一次加载模板时检查一次条件,然后停止检测更改,因为它会影响性能。
我希望页面在单次更改检测后像静态一样。
例如 :
<li *ngIf="doesHavePermission('templateName')">
</li>
Run Code Online (Sandbox Code Playgroud)
应该检查一次,但我看到的是它正在多次检查单身的变化*ngIf,我有很多*ngIf这样的:
我发现markForCheck()
和detach()这个角文档中https://angular.io/api/core/ChangeDetectorRef。
但他们正在做的是他们要么允许所有更改检测,要么根本不允许,
而且我只需要检测一次更改并在此之后停止。
我们可以在角度上进行单次时间变化检测吗?
或者有更好的方法来处理场景吗?
performance typescript angular2-changedetection angular angular-changedetection
假设我在屏幕上产生了100个div,*ngFor该div的值来自对象的数据,例如
{A1: someObject, A2: someOtherObject..., J10: someOtherOtherObject}
我单击A1,然后单击J10,它们切换其值。改为:
{A1: someOtherOtherObject, A2: someOtherObject..., J10: someObject}
如何强制Angular仅刷新仅包含A1和J10值的两个div?我正在使用ChangeDetectionStrategy.OnPush,在拥有的构造函数中cd.detach(),只有cd.detectChanges()在第二次单击发生时才调用。从我所看到和能够理解的角度来看,每个div都会触发它们,*ngIf因此将重新创建每个div 。
我可以做些什么来要么a)覆盖正在刷新的内容,要么b)选择检测更改所针对的内容?
angular2-changedetection angular angular-changedetection angular7
给定项目列表(将其视为与多条消息聊天),我想使用moment.js来显示每个项目的相对时间(例如,自创建以来)。
每个项目都有其自己的组成部分,并且使用以下代码显示相对时间:
get timeFromNow(): string {
return moment(this.pageLoaded).fromNow(); // pageLoaded is a JS Date
}
Run Code Online (Sandbox Code Playgroud)
问题是该组件不会更新相对时间的显示,因为原始输入(pageLoaded在上面的示例中)不会更改。
我的问题是:是否有应对这种情况的最佳实践?目前,我正在使用markForCheckof ChangeDetectorRef触发重新渲染。但是,我不确定这是否是一种性能良好的方法。
我已经在Stackblitz上创建了一个简单的演示。在演示中,我使用上述内容markForCheck触发更新。
我在我的视图中设置了一个内插值:
{{firstName}}
当它绑定到的字段的值发生变化时,它不会更新。但是,该值正在更改 - 如果我将其注销到订阅内的控制台,我会看到更新后的值。它只是不会在 UI 中更新。
这是相关的代码:
从我的组件订阅:
private subscribeToCurrentPerson(): void {
this.tState$ = this.store
.pipe(select(selectors.getCurrentPerson), takeWhile(() => this.componentActive))
.subscribe((cp: Person) => {
if (cp) {
const name: string = cp.primaryName.value.parsedValue.givenNames[0];
this.firstName = name;
console.log('name: ' + name); // <-- this shows correct new value
}
});
}
Run Code Online (Sandbox Code Playgroud)
subscribeToCurrentPerson从组件的 ngOnInit 调用。在此之前,该firstName属性是未定义的。
该selectors.getCurrentPerson选择是这样的:
export const getCurrentPerson: MemoizedSelector<{}, Person> =
createSelector(getTState, (tState: ITState) => {
console.log('selector: ', tState); // <-- …Run Code Online (Sandbox Code Playgroud) 我浏览了很多 SO 帖子,试图找到解决这个问题的方法,我发现唯一一个有 hack 实现的帖子。我也有一个来自我订阅的 ngrx 商店的可观察对象:
this.navigationSelected$ = this.store.pipe(select(currentlySelectedNavigation));
this.navigationSelected$.subscribe(res => {
...
});
Run Code Online (Sandbox Code Playgroud)
使用 ngIf 取决于模板内的这个可观察值:
<profile-navigation *ngIf="(navigationSelected$ | async) == navigationLayout[0].location"></profile-navigation>
Run Code Online (Sandbox Code Playgroud)
每当 navigationSelected$ 的值发生变化时,就会抛出:
ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'ngIf: [object Object]'. Current value: 'ngIf: false'.
Run Code Online (Sandbox Code Playgroud)
并且模板不会更新。我设法通过运行 cdRef.detectChanges(); 绕过它。在订阅结束时。它工作正常,但仍然抛出错误,而且如上所述,它似乎是一个黑客。
实现我想要做的事情的最佳方法是什么?
我引用了以下链接,仅在登录后启用注销按钮 https://stackblitz.com/edit/angular-login-hide-navbar-ngif
我只想在用户登录时在导航栏中显示“注销”,我通过从“身份验证服务”调用“this.authservice.isUserLoggedIn”并将其分配给变量并写入来验证用户是否已登录ngif“注销”链接附近的情况。我已经使用 BehaviourSubject 来获取当前状态。但我不知道为什么代码不起作用,它总是返回 false,因此即使用户登录后也不会启用“注销”链接
我有 header.component.ts
export class CommonheaderComponent implements OnInit {
constructor(private authservice : AuthenticationService) { }
isLoggedIn$ : Observable<boolean>;
ngOnInit() {
this.isLoggedIn$ = this.authservice.isUserLoggedIn;
}
}
Run Code Online (Sandbox Code Playgroud)
我有 header.component.html 如下
<ul class="nav navbar-nav">
<li><a [routerLink]='["/search"]'>Search <span class="slider"></span></a></li>
<li *ngIf="isLoggedIn"><a (click)="logout()">Logout</a></li>
</ul>
Run Code Online (Sandbox Code Playgroud)
下面是login.component.ts
export class LoginComponent implements OnInit {
isLoggedIn : Observable<boolean>;
ngOnInit() {
this.isLoggedIn = this.authservice.isUserLoggedIn;
this.loginForm = this.formbuilder.group({
username : ['', Validators.required],
password : ['', Validators.required]
})
}
}
onSubmit(){
this.authservice.login(this.loginForm.value).subscribe(data => {
}) …Run Code Online (Sandbox Code Playgroud) typescript behaviorsubject angular angular-changedetection angular7
我想知道以下情况会发生什么:
我有一个带有这些控件的 formGroup:
{
forename: new FormControl()
surname: new FormControl()
}
Run Code Online (Sandbox Code Playgroud)
现在我像这样跟踪控件“姓氏”的变化(只是一个例子):
this.formGroup.get('surname').valueChanges.subscribe(changes => {
if(this.formGroup.get('forename') == 'Max'){
this.formGroup.get('forename').disable();
}
})
Run Code Online (Sandbox Code Playgroud)
最后我像这样修补我的表单:
this.formGroup.patchForm({surname: 'Muster', forename: 'Max'});
控件“名字”会被禁用吗?因为我不确定它是否会在设置控件“名字”的值之前触发控件“姓氏”的更改。因此,“名字”可能还没有“正确”值。
我试图更好地理解,当触发确切的 valueChanges 事件时,因为我有时会遇到问题,但值没有设置,尽管它们应该设置。
我还想知道是否可以等到每个控件都修补完毕然后发出更改。
我有 2 个组件 - 父组件和子组件。请参阅stackblitz 演示
父级模板如下所示 -

单击“显示子组件”时,isChild1Visible 设置为 true,导致子组件显示其模板。

当您单击“隐藏我”时,子组件将 isVisible 设置为 false,从而使其被隐藏。现在,当再次单击“显示子组件”时,子组件将不会显示。
我在子组件中添加 ngOnChanges() 以查看更改检测,但是在初始化子组件时我看到以下内容:

单击“隐藏我”后,即使稍后单击“显示我”,ngOnChanges()也不会打印任何内容。
那么,为什么在子组件中更新输入属性后更改检测停止工作?
下面是在一个子组件上调用的更改函数,以更改selectedName其他两个子组件中的@Input字符串类型,如果我将其更改为对象,它可以正常工作。
我有一个简单的<div>生成 using*ngFor指令列表,类似于
<div *ngFor="let item of items() | async ; let i=index"
[ngClass]="getItemClass(i)"
(click)="itemClick(i)"</div>
Run Code Online (Sandbox Code Playgroud)
如您所见,该方法返回的 Observable 每次items()发出时都会异步填充列表。在我的情况下,这样的 Observable 是 a ReplaySubject,如果这对知道有任何用处。然后我<div>使用方法定义要应用于每个元素的类getItemClass。
我还想使用方法对每个项目上的点击事件做出反应itemClick(i: number)。
问题
任何时候div单击一个元素,即任何时候itemClick(i: number)运行该方法,似乎<div>都重建了整个s列表。我得出这个结论是观察到任何时候div点击一个元素,该items()方法也会运行。
题
<div>单击其中一个元素时是否可以避免重建列表?我已经设置changeDetection为OnPush但它似乎并没有解决我的问题。
我想在子组件初始化后从父组件对子组件进行一些操作。
export class ParentComponent implements AfterViewInit {
@ViewChild('child') childComponent: ChildComponent;
ngAfterViewInit() {
this.childComponent.domMethod('boo');
}
}
Run Code Online (Sandbox Code Playgroud)
<p>parent</p>
<app-child #child></app-child>
Run Code Online (Sandbox Code Playgroud)
<p>parent</p>
<app-child #child></app-child>
Run Code Online (Sandbox Code Playgroud)
<p>child</p>
<input type="text" id="childInput" [(ngModel)]="term">
<ul>
<li *ngFor="let item of items | search: term">{{item.name}}</li>
</ul>
Run Code Online (Sandbox Code Playgroud)
链接到StackBlitz以进行复制
如果我添加setTimeout到父组件,它就可以工作。我可以在没有的情况下实现setTimeout吗?
export class ChildComponent implements OnInit {
constructor(private readonly cdr: ChangeDetectorRef,) {
}
public term = '';
public items;
ngOnInit() {
this.items = [
{ name: 'foo' },
{ name: 'bar' },
{ name: …Run Code Online (Sandbox Code Playgroud) angular ×12
typescript ×3
angular7 ×2
momentjs ×1
ngonchanges ×1
ngrx ×1
ngzone ×1
performance ×1
rxjs ×1