angular - 以编程方式使用 AsyncPipe - Angular 2

标签 angular angular-pipe

我正在使用一个组件来渲染表格之类的数据,我给它列列表、数据、数据如何映射到每列,最后是一个应用于每列数据的管道列表。

到目前为止一切顺利,唯一的问题是当这些管道之一是异步管道时......

经过一段时间的实验,我发现当在模板上使用 asyncpipe 时,transform 方法会被调用多次。但是,如果我以编程方式使用它,则转换方法仅被调用一次(当我调用它时)。

我猜它在模板上被多次调用的原因是因为它是一个不纯的管道,但是我如何以编程方式处理它?<​​/p>

这是一个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(),我还尝试了以下操作:

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);
  }
}

没有任何成功:(

最佳答案

经过一番努力,我终于得到了一些结果,这就是我必须做的,以供将来引用。

第一种方法: 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),因为 finally 似乎返回一个新对象,而不是修改现有对象。 最后是repeat(2),这样它将解开promise。

<小时/>

第二种方法: 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 毫秒重新计算一次管道,简单而有效,尽管我期待更好的结果。

<小时/>

final方法: 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 两次来解开值。

<小时/>

无论如何,希望它能真正帮助那些因编程处理非纯管道而感到沮丧的人!

仍然欢迎任何建议或更好的答案!

关于angular - 以编程方式使用 AsyncPipe - Angular 2,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45297666/

相关文章:

组件中管道过滤器的 angular2 错误

angular - 如何在异步管道上使用自定义管道?

date - 将管道或转换应用到响应式表单值

node.js - 将 Angular 更新到版本 8 后出现错误

Angular CLI - 获取覆盖率报告以包括所有来源

javascript - 无法处理 Angular 2+ 中的意外错误

Angular 4 - 如何在输入类型中使用货币管道

html - Angular动态添加类

angular - Typescript - 代码无法从错误 TS1128 : Declaration or Statement expected, 生成,但在我提供代码时按预期运行

javascript - Angular 2 过滤管