Angular 8 UI observable 未触发更改检测 - ChangeDetectionStrategy 设置为默认值
Angular 8 UI observable not triggering change detection - ChangeDetectionStrategy is set to default
我有一个容器组件,其中注入了一项服务。该服务包含一个可观察的。在容器组件的模板中,我使用异步管道将该可观察对象绑定到 child 组件的输入 属性。一切似乎都正常,除了我必须与 UI 交互才能触发更改检测并显示通过可观察对象推送的数据。
(不更新是指似乎:child 组件 html 中的 <ng-container *ngFor="let section of sections;">
未执行)
我已经尝试了很多事情,包括在 parent 组件中创建另一个可观察对象,并通过该可观察对象从服务中继数据——但这只是一种故障排除措施,而且非常笨拙。我相信它有相同的结果。
注:
1. The service is pulling data from a .net backend via a socket (SignalR).
2. I am also using Angular Material's drag and drop library in this project.
3. **This post seems very similar**, but I can't discern a cause or solution from it:
4. I mention 3 because that person was using angular material's infinite scrolling library and I am using drag and drop. Maybe something in that library is interfering with change detection.
5. There is no OnPush change detection anywhere in this project
服务:
export class DocumentCreationService {
private library = new Subject<DocumentSection[]>();
public library$ = this.library.asObservable();
...
private registerOnServerEvents(): void {
this.proxy.on('documentSectionsRetrieved', (result: DocumentSection[]) => {
this.library.next(result);
});
}
...
public retrieveDocumentSections = () => {
this.proxy.invoke('getDocumentSections')
.then(() => console.log("getDocumentSections completed"))
.catch(err => console.error(err));
}
...
}
容器 ts:
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss']
})
export class HomeComponent {
...
constructor(public documentCreator: DocumentCreationService) { }
}
容器html:
<document-section-library #library [hidden]="selectedView !== 'library'" [sections]="documentCreator.library$ | async" [connectedDropTargets]="dropTargets">
Child 时间:
@Component({
selector: 'document-section-library',
templateUrl: './document-section-library.component.html',
styleUrls: ['./document-section-library.component.scss']
})
export class DocumentSectionLibraryComponent {
...
@Input()
public sections: DocumentSection[];
...
Child html:
<div class="document-section-library__contentarea" cdkDropList id="sectionLibrary" #sectionLibrary="cdkDropList" [cdkDropListConnectedTo]="connectedDropTargets" [cdkDropListData]="sections" (cdkDropListDropped)="onDrop($event)">
<ng-container *ngFor="let section of sections;">
<ng-template [ngIf]="section.content && section.content.length > 0" [ngIfElse]="table">
<document-section-custom class="document-section" cdkDrag
[id]="section.id"
[templateId]="section.templateId"
[name]="section.name"
[enabled]="section.enabled"
[content]="section.content">
</document-section-custom>
</ng-template>
<ng-template #table>
<document-section-table class="document-section" cdkDrag
[id]="section.id"
[templateId]="section.templateId"
[name]="section.name"
[enabled]="section.enabled"
[content]="section.content">
</document-section-table>
</ng-template>
</ng-container>
</div>
我希望 UI 能够立即反映通过 observable 推送的数据,而无需单击某些内容或以其他方式与 UI 交互。
在这种情况下,我尝试使用可观察对象来执行此操作,因为我似乎也无法以任何其他方式让它工作。
最终,我真正想要的是在服务中只拥有一个 DocumentSection 数组作为 public 属性,通过服务上的方法更新该数组,并进行更改立即反映到数组中。我不确定我什至真的需要一个可观察的。我希望服务上的 属性 像组件上的本地 属性 一样。
所以两个问题:
这个变化检测问题是怎么回事,我该如何解决?
为什么我不能(或可以),只需在服务上创建一个 public 数组并正常绑定它(不通过异步管道)并让它在同一个环境中工作如果它是容器组件上的 public 属性 会怎样?
也许发生的事情是他们订阅(async
在容器视图中)发生在初始文档到达之后,所以 Angular 没有接收到该排放?
我会尝试改变:
private library = new Subject<DocumentSection[]>();
到
private library = new BehaviorSubject<DocumentSection[]>([]);
或者,您可以尝试完全不使用可观察对象,并绑定到通过 getter.
访问的基本数组
private _library = []; // update when data is fetched
public get library() { return this._library || []; } // data-bind this
最终这似乎是某种 conflict/issue 与 Angular 和 JQuery and/or signalr(pre .net core)库 - 那个 signalr 库有对 JQuery 的依赖。我用更新的 .NET Core 版本替换了 signalr 库(当然我也将后端更新为 .NET Core)并删除了 JQuery 并且一切正常。我希望我能为其他遇到此问题的人找到更好的根本原因,但在与此抗争 48 小时后,我很高兴继续前进。
如果有人 thoughts/ideas 关于这两个库可能导致问题的原因,我仍然很感兴趣。
我有一个容器组件,其中注入了一项服务。该服务包含一个可观察的。在容器组件的模板中,我使用异步管道将该可观察对象绑定到 child 组件的输入 属性。一切似乎都正常,除了我必须与 UI 交互才能触发更改检测并显示通过可观察对象推送的数据。
(不更新是指似乎:child 组件 html 中的 <ng-container *ngFor="let section of sections;">
未执行)
我已经尝试了很多事情,包括在 parent 组件中创建另一个可观察对象,并通过该可观察对象从服务中继数据——但这只是一种故障排除措施,而且非常笨拙。我相信它有相同的结果。
注:
1. The service is pulling data from a .net backend via a socket (SignalR).
2. I am also using Angular Material's drag and drop library in this project.
3. **This post seems very similar**, but I can't discern a cause or solution from it:
4. I mention 3 because that person was using angular material's infinite scrolling library and I am using drag and drop. Maybe something in that library is interfering with change detection.
5. There is no OnPush change detection anywhere in this project
服务:
export class DocumentCreationService {
private library = new Subject<DocumentSection[]>();
public library$ = this.library.asObservable();
...
private registerOnServerEvents(): void {
this.proxy.on('documentSectionsRetrieved', (result: DocumentSection[]) => {
this.library.next(result);
});
}
...
public retrieveDocumentSections = () => {
this.proxy.invoke('getDocumentSections')
.then(() => console.log("getDocumentSections completed"))
.catch(err => console.error(err));
}
...
}
容器 ts:
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss']
})
export class HomeComponent {
...
constructor(public documentCreator: DocumentCreationService) { }
}
容器html:
<document-section-library #library [hidden]="selectedView !== 'library'" [sections]="documentCreator.library$ | async" [connectedDropTargets]="dropTargets">
Child 时间:
@Component({
selector: 'document-section-library',
templateUrl: './document-section-library.component.html',
styleUrls: ['./document-section-library.component.scss']
})
export class DocumentSectionLibraryComponent {
...
@Input()
public sections: DocumentSection[];
...
Child html:
<div class="document-section-library__contentarea" cdkDropList id="sectionLibrary" #sectionLibrary="cdkDropList" [cdkDropListConnectedTo]="connectedDropTargets" [cdkDropListData]="sections" (cdkDropListDropped)="onDrop($event)">
<ng-container *ngFor="let section of sections;">
<ng-template [ngIf]="section.content && section.content.length > 0" [ngIfElse]="table">
<document-section-custom class="document-section" cdkDrag
[id]="section.id"
[templateId]="section.templateId"
[name]="section.name"
[enabled]="section.enabled"
[content]="section.content">
</document-section-custom>
</ng-template>
<ng-template #table>
<document-section-table class="document-section" cdkDrag
[id]="section.id"
[templateId]="section.templateId"
[name]="section.name"
[enabled]="section.enabled"
[content]="section.content">
</document-section-table>
</ng-template>
</ng-container>
</div>
我希望 UI 能够立即反映通过 observable 推送的数据,而无需单击某些内容或以其他方式与 UI 交互。
在这种情况下,我尝试使用可观察对象来执行此操作,因为我似乎也无法以任何其他方式让它工作。
最终,我真正想要的是在服务中只拥有一个 DocumentSection 数组作为 public 属性,通过服务上的方法更新该数组,并进行更改立即反映到数组中。我不确定我什至真的需要一个可观察的。我希望服务上的 属性 像组件上的本地 属性 一样。
所以两个问题:
这个变化检测问题是怎么回事,我该如何解决?
为什么我不能(或可以),只需在服务上创建一个 public 数组并正常绑定它(不通过异步管道)并让它在同一个环境中工作如果它是容器组件上的 public 属性 会怎样?
也许发生的事情是他们订阅(async
在容器视图中)发生在初始文档到达之后,所以 Angular 没有接收到该排放?
我会尝试改变:
private library = new Subject<DocumentSection[]>();
到
private library = new BehaviorSubject<DocumentSection[]>([]);
或者,您可以尝试完全不使用可观察对象,并绑定到通过 getter.
访问的基本数组private _library = []; // update when data is fetched
public get library() { return this._library || []; } // data-bind this
最终这似乎是某种 conflict/issue 与 Angular 和 JQuery and/or signalr(pre .net core)库 - 那个 signalr 库有对 JQuery 的依赖。我用更新的 .NET Core 版本替换了 signalr 库(当然我也将后端更新为 .NET Core)并删除了 JQuery 并且一切正常。我希望我能为其他遇到此问题的人找到更好的根本原因,但在与此抗争 48 小时后,我很高兴继续前进。
如果有人 thoughts/ideas 关于这两个库可能导致问题的原因,我仍然很感兴趣。