General
I have a problem. My component does not re-render without calling changeDetectorRef.markForCheck
method.
I have an autocomplete. When input changes I send some async request (just simple HttpClient service and get
method). After that, I fill in some internal state.
The code
Note markForCheck
call. If I remove this line: nothing works. I noticed that if I remove it and if I click somewhere outside of the component, I see re-render. Right in time when I click somewhere component is re-rendered.
By the way, I realized that markForCheck
is working by accident. I just tried something and it worked. I got info about CD mechanisms and CD service from some articles.
Here is my main component:
@Component({
selector: 'tags-auto-complete',
template: `
<tags-internal-auto-complete-input
// ....
(inputChanged)="onInputChange($event);"
></tags-internal-auto-complete-input>
<tags-internal-auto-complete-results
[data]="queryResultsTags"
// ....
></tags-internal-auto-complete-results>
`,
})
export class TagsAutoCompleteContainerComponent implements OnInit {
inputChanged = new Subject<string>();
queryResultsTags: Tag[] = [];
constructor(
private tagsService: TagsService,
private changeDetectorRef: ChangeDetectorRef,
) {}
onInputChange(query: string): void {
this.inputChanged.next(query);
}
ngOnInit() {
this.inputChanged
.filter(inputValue => inputValue.length > 0)
.debounceTime(400)
.switchMap(query => this.tagsService.getTagsList({ query }))
.do(() => this.changeDetectorRef.markForCheck()); // note this
.subscribe((tags: Tag[]) => (this.queryResultsTags = tags)) // here I change the input of inner component
}
// ...
Here is child component (tags-internal-auto-complete-results
):
@Component({
selector: 'tags-internal-auto-complete-results',
template: `
<div class="container">
<span *ngFor="let tag of data" (click)="selectTag.emit(tag);" class="tag">
{{tag.name}}
</span>
</div>
`,
styleUrls: ['./results.styles.css'],
})
export class TagsAutoCompleteResultsComponent {
@Input() data: Tag[] = [];
@Output() selectTag = new EventEmitter<Tag>();
}
These are just fragments. Whole code is available on GitHub.
By the way, I have another component (selected tags block) and I have input showLoader
in it. It has exactly same problem.
My thoughts
Probably problem somehow connected to the zones mechanism. From some articles I know, that zone.js monkey-patches some events or XHR calls. And my case is XHR call (I didn't dive deep into HttpClient but it must just make an HTTP call).
What I want
I want to understand why changes are not detecting out of the box there (so I will use markForCheck and I will be ok) or I want to find a mistake in my code.
Hope you will help me there.