У меня есть дочерний компонент, который является полем поиска. Пользователь вводит некоторые данные и нажимает кнопку поиска. Это испускает событие «поиска», когда родительский компонент затем вызывает службу поиска с параметрами поиска и присваивает результат признаку входного свойства дочернего компонента. В установщике входного свойства дочернего компонента я подписываюсь на Observable, а затем сопоставляю результаты. Моя проблема заключается в том, что пользовательский интерфейс не будет обновляться, когда результаты будут установлены до тех пор, пока не произойдет событие, такое как перемещение мыши или нажатие кнопки. Я думаю, мне нужно позвонить в подписку, используя ngZone. Мой вопрос: зачем мне это делать? В альтернативном вкусе моего компонента поиска родительский компонент отвечает за вызов подписки, а затем присваивает результаты входному свойству дочернего компонента, и это работает как ожидалось. Было бы очень полезно понять, что отличает эти два подхода и лучший способ их решения.Angular 2 Observable Input не обновляет пользовательский интерфейс после подписки
Ниже приведено мое поле поиска (ребенок).
import {
AfterViewInit, ChangeDetectorRef, ChangeDetectionStrategy, Component,
ElementRef, EventEmitter, Input, OnChanges,
Output, SimpleChanges, ViewChild } from '@angular/core';
import { ControlValueAccessor } from '@angular/forms';
import {
ApplicationService, PromptActions, PromptType,
SearchItem, SearchItemType, SearchType, SearchArgs,
UserPromptRequest
} from '../../../core';
import { Observable } from 'rxjs/Observable';
import { Subscription } from 'rxjs/Subscription';
import { PanelBarItemModel } from '@progress/kendo-angular-layout';
@Component({
moduleId: module.id,
selector: 'search-box',
templateUrl: 'search-box.component.html',
styleUrls: ['search-box.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class SearchBoxComponent implements ControlValueAccessor {
constructor(private cd: ChangeDetectorRef, private applicationService: ApplicationService) { }
@Input() searchText: string;
@Output() search: EventEmitter<SearchArgs> = new EventEmitter();
private _searchObservable: Observable<SearchItemType[]>;
@Input()
set searchObservable(val: Observable<SearchItemType[]>) {
this._searchObservable = val;
if (this._searchObservable) {
this.searchSubscription = this._searchObservable.subscribe(r => this.resp(r));
}
}
private _selectedItem: SearchItem;
@Input()
set selectedItem(val: SearchItem) {
this._selectedItem = val;
this.propagateChange(this._selectedItem);
}
get selectedItem(): SearchItem {
return this._selectedItem;
}
searchResultsModel: PanelBarItemModel[];
private _searchResults: SearchItemType[];
@Input()
set searchResults(val: SearchItemType[]) {
this._searchResults = val;
this.setUpPanelBarModel();
}
get searchResults(): SearchItemType[] {
return this._searchResults;
}
private setUpPanelBarModel() {
this.isSearching = false;
this.cd.markForCheck();
}
onSearch() {
this.isResultsPopupVisible = true;
this.searchResults = undefined;
let searchArgs = new SearchArgs(this.searchText, this.selectedSearchTypeValue);
this.search.emit(searchArgs);
this.isSearching = true;
this.cd.markForCheck();
}
resp(r: any) {
this.searchResults = r;
this.cd.markForCheck();
}
writeValue(obj: any): void {
this.selectedItem = obj;
}
private propagateChange = (_: any) => { };
registerOnChange(fn: any): void {
this.propagateChange = fn;
}
registerOnTouched(fn: any): void { } // Don't need
}
Ниже приводится код родительского компонента. Если я мгновенно обмениваюсь прокомментированной и раскоментированной строкой в onSearch, мой результат отображается мгновенно. В противном случае мне нужно вызвать еще один Угловой пользовательский интерфейс, перемещая мышь, нажимая или нажимая клавишу. Большое спасибо за любую помощь!
import { ChangeDetectorRef, ChangeDetectionStrategy, Component } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { SettingsEntityListComponentBase } from '../../component-bases';
import { ClientType } from '../../models/ClientType';
import { ClientTypeService } from '../../services/client-type.service'
import {
ApplicationService, NotificationContext,
Permission, UserService, WindowType, SearchArgs,
SearchItem, SearchItemType, SearchTypeValues
} from '../../../core';
@Component({
moduleId: module.id,
selector: 'client-type-list',
templateUrl: 'client-type-list.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ClientTypeListComponent extends SettingsEntityListComponentBase<ClientType> {
constructor(
changeDetector: ChangeDetectorRef,
appService: ApplicationService,
clientTypeService: ClientTypeService,
userService: UserService) {
super(changeDetector, appService, clientTypeService, userService, Permission.SettingsClientTypes,
Permission.GlobalClientTypes, WindowType.ClientTypeDetail, NotificationContext.ClientTypeChanged);
}
searchText: string = '4455';
selectedSecurity: SearchItem;
searchObservable: Observable<SearchItemType[]>;
searchResults: SearchItemType[];
onSearch(args: SearchArgs): void {
this.searchObservable = this.appService.search(args.searchText, SearchTypeValues.Securities);
//this.appService.search(args.searchText, SearchTypeValues.Securities).subscribe(r => this.resp(r));
}
resp(r: any) {
this.searchResults = r;
this.changeDetector.markForCheck();
}
}