2017-07-25 77 views
1

我使用一個組件來渲染表格,如數據,我給它列,數據,數據如何映射到每列,最後是一個管道列表應用於每列數據。以編程方式使用AsyncPipe - Angular 2

到目前爲止好,唯一的問題是,當這些管道的一個是異步管......

經歷過了一些時間後,我發現,當asyncpipe是在模板中使用的變換方法獲得多次呼籲。但是,如果我以編程方式使用它,則變換方法只會被調用一次(我調用它的時間)。

我猜它在模板上被多次調用的原因是因爲它是不純的管道,但是如何以編程方式處理它?

這裏有一個plunker證明什麼,我只是說:

@Injectable() 
export class AsyncProvider { 
    constructor() {} 

    getById(id: number) { 
    // Just some mock data 
    return Observable.of({id, times_five: id*5}).delay(1000); 
    } 
} 

@Component({ 
    selector: 'my-app', 
    providers: [AsyncPipe, AsyncProvider] 
    template: ` 
    <div> 
     <p>Template async pipe</p> 
     <p>{{ asyncObj | async | json }}</p> 
     <hr> 
     <p>Programmatically async pipe</p> 
     <p>{{ asyncObjPiped | json }}</p> 
    </div> 
    `, 
    directives: [] 
}) 
export class App { 
    constructor(
    private _provider: AsyncProvider, 
    private _async: AsyncPipe 
) { 
    this.asyncObj = this._provider.getById(123); 
    this.asyncObjPiped = this._async.transform(this.asyncObj); 
    } 
} 

編輯: 因爲AsyncPipe執行上ChangeDetectorRef一個markForCheck()uppon接收新的價值觀,我也試過如下:

export class App { 
    constructor(
    private _provider: AsyncProvider, 
    private _async: AsyncPipe, 
    private _ref: ChangeDetectorRef, 
) { 
    this.asyncObj = this._provider.getById(123); 
    this.asyncObjPiped = this._async.transform(this.asyncObj); 

    setInterval(() => { 
     this._ref.detectChanges(); 
    }, 1000); 
    } 
} 

沒有任何成功:(

+0

你是什麼意思**以編程方式處理**你想做什麼? – Alex

+0

@ AJT_82我希望它表現得就好像我在模板中使用管道(詳見plunker),但是,由於方法asyncPipe作品(SRC可以在這裏找到代碼:https://github.com/angular/angular /blob/master/packages/common/src/pipes/async_pipe.ts)所述管具有被多次調用,用於發射正確的結果。這似乎可以解釋爲什麼asyncpipe不是純粹的原因,但我想不出任何如何「模仿」這種非純粹的行爲編程控制器上,也沒有我有什麼想法,其中在角碼是。 – Ignasi

回答

0

經過一番掙扎之後,我設法得到了一些結果,這是我必須做的,以備將來參考。

第一種方法: plunker

export class App { 
    constructor(
    private _provider: AsyncProvider, 
    private _async: AsyncPipe, 
) { 

    this.asyncObj = this._provider.getById(123) 

    let processPipe =() => { 
     this.asyncObjPiped = this._async.transform(new_asyncObj); 
    } 
    let new_asyncObj = this.asyncObj.finally(processPipe).repeat(2); 
    processPipe(); 
    } 
} 

注意,需要一個新的變量(new_asyncObj),因爲似乎終於返回一個新的對象,而不是修改現有的。 和最後的重複(2),所以它會解開承諾。


方法二: plunker

export class App { 
    constructor(
    private _provider: AsyncProvider, 
    private _async: AsyncPipe, 
) { 

    this.asyncObj = this._provider.getById(123) 

    setInterval(() => { 
     this.asyncObjPiped = this._async.transform(this.asyncObj); 
    }, 500); 

    } 
} 

重新計算管道每隔500毫秒,簡單而有效的,即使我期待更好的東西。


最後一個方法: plunker

export class App { 
    constructor(
    private _provider: AsyncProvider, 
    private _async: AsyncPipe, 
    private _ref: ChangeDetectorRef, 
    private zone: NgZone, 
) { 

    this.asyncObj = this._provider.getById(123) 

    this.zone.onMicrotaskEmpty 
     .subscribe(() => { 
     this.asyncObjPiped = this._async.transform(this.asyncObj); 
     this.asyncObjPiped = this._async.transform(this.asyncObj); 
     this._ref.detectChanges(); 
     }); 
    } 
} 

使用NgZone和ChangeDetectorRef似乎藏漢工作,甚至想到了一些醜陋的黑客攻擊,調用AsyncPipe兩次,拆開包裝的價值。


無論如何,希望它可以真正幫助任何人在編程上處理非純管道時感到沮喪!

任何建議或更好的答案仍然歡迎!

+0

我喜歡使用異步管的想法,因爲它觸發OnPush變化檢測(其中,手動訂閱沒有)。而且經常需要在方法中觀察到的變量。給你一個讓這個工作的一切。這就是說......如果有一個更清晰,更有文件記錄的方式來做這件事,那將會很不錯。 –