繁体   English   中英

如何在 Angular 中创建与另一个组件关联的自己的组件生命周期回调?

[英]How do I create my own component lifecycle callback associated with another component in Angular?

我很难掌握 Angular 和 Promises 的窍门。 我正在尝试为角度数据表创建另一层包装器以添加一些通用自定义,然后让基础组件知道它已完成并允许访问该实例变量。 非常类似于 ngAfterViewInit,但“parentNgAfterViewInit”——我将其命名为 dtAfterInit。

app.component.ts (1 级/基础)

export class AppComponent implements OnInit, OnDestroy {
  ngOnInit(): void {
   this.http.get<any[]>("./assets/data/data.json").subscribe(datas => {
   this.datas = datas;
   this.dtTrigger.next();
   });
  });
 }

  ngOnDestroy(): void {
    this.dtTrigger.unsubscribe();
  }

  dtAfterInit(dtInstance: DataTables.Api): void {
    //@todo
  }
}

app.component.html (1级/基地)

  <datatable
    [dtOptions]="dtOptions"
    [dtTrigger]="dtTrigger"
    paginationLength="true"
    filter="true"
    tableClass="table table-striped table-bordered table-hover"
    width="100%"
  >
    <thead>
     <!-- THEAD -->
    </thead>
    <tbody>
     <!-- TBODY -->
    </tbody>
  </datatable>

datatable.component.ts (2级)

@Component({
  selector: "datatable",
  template: `
    <table
      datatable
      [dtOptions]="dtOptions"
      [dtTrigger]="dtTrigger2"
      class="dataTable responsive {{ tableClass }}"
      width="{{ width }}"
    >
      <ng-content></ng-content>
    </table>
  `
})
export class DatatableComponent implements OnInit, OnDestroy {
  @ViewChild(DataTableDirective, { static: false })
  datatableElement: DataTableDirective;

  /** <DataTables Inputs> */
  @Input() public dtOptions: DataTables.Settings = {};
  @Input() public dtTrigger: Subject<any> = new Subject();
  /** </DataTables Inputs> */

  private dtTrigger2: Subject<any> = new Subject();

      ngOnInit(): void {
        if (this.dtTrigger) {
          this.dtTrigger.subscribe(() => {
            this.dtTrigger2.next();
            this.datatableElement.dtInstance.then((dtInstance: DataTables.Api) => {
              //window["test"] = dtInstance; //Give this instance over to the AppComponent
              //@todo AppComponent.dtAfterInit(dtInstance)
            });
          });
        }
      }
    
      ngOnDestroy(): void {
        this.dtTrigger2.unsubscribe();
      }
    
      /** Attempt #2, but
       *  This doesn't quite work because it isn't guaranteed that (the HTTP request is completed prior to this)
       *  this.dtTrigger.next() got called yet, so this.datatableElement.dtInstance could be null
      ngAfterViewInit(): void {
        this.datatableElement.dtInstance.then((dtInstance: DataTables.Api) => {
          window["test"] = dtInstance; //Give this instance over to the AppComponent
          //@todo AppComponent.dtAfterInit(dtInstance)
        });
      } */
  1. 如何让 AppComponent 知道 dtInstance 已初始化,并为该组件提供实例?

在@todo 中,dtInstance 已成功初始化。 现在我想将此变量从DatatableComponent传递回AppComponent ,并让它从这个时间点(在它被初始化之后)执行任何额外的单个组件级事件绑定,或者只是为了能够直接访问数据表 API .

  1. 我怎样才能更“Angular-ly”做到这一点?

在上面的例子中,我试图创建两个 / 嵌套的主题,这样当 AppComponent 下一次触发时,它会触发 DatatableComponent 触发器,然后触发 DataTableDirective(角度数据表包装库),所以我们可以做我们的 dtAfterInit 回调这里。 但我想这很丑陋而且不是很“Angular”,此外,我使用window["test"] = dtInstance使 dtInstance 成为全局变量,以便 AppComponent 可以访问它以更好地说明我正在尝试做的事情.

是否有事件可以保证 http.get() 完成,因此 dt 也被初始化? 我已经尝试过 ngAfterViewInit,但我不相信这有效,因为 this.dtTrigger.next() 尚未触发,所以 dtInstance 是 null。 这里最好的方法是直接修改 angular-datatables 包装器吗?

angular-datatables.directive.ts (3 级)

@Directive({
  selector: '[datatable]'
})
export class DataTableDirective implements OnDestroy, OnInit {
  dtInstance: Promise<DataTables.Api>;
  ngOnInit(): void {
    if (this.dtTrigger) {
      this.dtTrigger.subscribe(() => {
        this.displayTable();
      });
    } else {
      this.displayTable();
    }
  }
  private displayTable(): void {
    this.dtInstance = new Promise((resolve, reject) => {
      Promise.resolve(this.dtOptions).then(dtOptions => {
        // Using setTimeout as a "hack" to be "part" of NgZone
        setTimeout(() => {
          this.dt = $(this.el.nativeElement).DataTable(dtOptions);
          resolve(this.dt);
        });
      });
    });
  /* @attempt#3, I'm thinking maybe directly modifying this library be the best way? If there isn't an event I can use, or to avoid having the two trigger to just one
     ex. Promise.resolve(this.dtInstance).then(
              //@todo AppComponent.dtAfterInit(dtInstance)
         );
  */
  }

这是我尝试的完整代码的沙盒链接

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM