2016-12-19 69 views
0

我有一個子組件,它是一個搜索框。用戶鍵入一些輸入並按下搜索按鈕。這會發出一個「搜索」事件,父組件隨後使用搜索參數調用搜索服務,並將結果分配給子組件的Observable輸入屬性。在子組件輸入屬性的setter中,我訂閱Observable,然後映射結果。我的問題是,當結果設置之前,UI不會刷新,直到發生諸如鼠標移動或按鈕點擊之類的事件。我想我需要使用ngZone來調用訂閱我的問題是爲什麼我必須這樣做?在我的搜索組件的另一種風格中,父組件負責調用訂閱,然後將結果分配給子組件的輸入屬性,並按預期工作。對於這兩種方法有什麼不同以及解決的最佳方式,我們真的很感激。Angular 2 Observable輸入訂閱後不更新UI

以下是我的搜索框(兒童)組件。

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結果顯示中立即交換註釋和未註釋行。否則,我需要通過移動鼠標,單擊或按下一個鍵來觸發另一個Angular UI tick。非常感謝您的幫助!

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性質改變檢測。否則,您必須手動通知Angular有關更改。

嘗試將服務的搜索結果連接到您用來顯示結果(ClientTypeListComponent.searchResults ??)的@Input屬性。此外,我不確定如何/如果更改檢測與SearchBoxComponent.searchResults的getter/setter一起使用;您可以嘗試將其重寫爲正常的@Input屬性。