2016-12-19 67 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属性。