2016-12-19 2 views
0

У меня есть дочерний компонент, который является полем поиска. Пользователь вводит некоторые данные и нажимает кнопку поиска. Это испускает событие «поиска», когда родительский компонент затем вызывает службу поиска с параметрами поиска и присваивает результат признаку входного свойства дочернего компонента. В установщике входного свойства дочернего компонента я подписываюсь на 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(); 
    } 
} 

ответ

0

С помощью ChangeDetectionStrategy.OnPush вы ограничены, чтобы изменить обнаружение с помощью @Input и @Output свойств. В противном случае вы должны вручную уведомить об этом изменения.

Пробуйте соединить результаты поиска из сервиса до объекта @Input, которое вы используете для отображения результатов (ClientTypeListComponent.searchResults ??). Кроме того, я не уверен, как/если обнаружение изменений работает с getter/setter от SearchBoxComponent.searchResults; вы можете попробовать переписать его как обычно @Input.