2017-07-25 74 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变化检测(其中,手动订阅没有)。而且经常需要在方法中观察到的变量。给你一个让这个工作的一切。这就是说......如果有一个更清晰,更有文件记录的方式来做这件事,那将会很不错。 –