【问题标题】:How to wait for component drawn or what to do when Angular "serve" is working but "build" isn't?如何等待组件绘制或当 Angular“服务”工作但“构建”不工作时该怎么办?
【发布时间】:2019-07-10 07:16:37
【问题描述】:

我创建了一个组件,该组件获取包含表数据的数组。另一个组件绘制表格。然后我得到innerHTML 并将其放入tinyMCE。

这在ng serve 中非常有效,但是当我创建ng build --prod 时,表是空的并且没有可用的数据。

ngOnInit() {
    this.data = JSON.parse(JSON.stringify(this.data));

    this.tabledata = this.data.protocol;
    this.tinymceModel = "";


        setTimeout(() => {
            let root = document.querySelectorAll('[name="tabledatas"]')

            Object.values(root).forEach(elem => {
                let result = elem.innerHTML;
                    result = result.replace(/<!--.*-->/g,'')
                    result = result.replace(/\t|\n/g,'')
                    result = result.replace(/<tfoot>.*<\/tfoot>/g,'')

                this.tinymceModel = this.tinymceModel + result;
            })
        })
...
}

代码如下所示。我相信setTimeout 会等到数据可用,但它似乎无法正常工作。我的错误在哪里,或者在最终绘制表格时如何确保继续?

【问题讨论】:

    标签: angular tinymce settimeout ngoninit


    【解决方案1】:

    我不会直接回答您的问题,而是向您提供一些观察和相应的建议:

    拆分数据并跨两个组件进行渲染

    您描述了两个组件,其中一个处理数据检索,另一个处理您的数据呈现。最有可能的是,您随后通过 Input() / Output() 在两者之间传递数据。

    相反,请考虑使用 服务 来处理您的数据交互,并通过依赖注入将这些数据提供给您的组件。 Here's the official tutorial on services using the Tour of Heroeshere is a great introduction to dependency injection in Angular

    直接访问 DOM / innerHTML 属性以将数据传递给您的模板

    只有极少数情况下访问 DOM / 元素的 innerHTML 属性应该被视为首选。相反,看看the TinyMCE Angular Component,申请你的案例很可能比直接访问 DOM 容易得多。

    使用不带毫秒参数的 setTimeout()

    这将使用时间值为 0 的 setTimeout。有几个用例可以“让渲染器赶上”或使用它来等待 nodeJS 中的下一个微任务完成。 Here is a detailed answer on when and how this may be necessary.

    ng serveng build --prod

    我怀疑您的问题的原因在于servebuild,使用ng serve --prod 很可能会对您的程序产生相同的影响。查看this video,了解开发和生产版本之间的差异。

    【讨论】:

      【解决方案2】:

      我们不应该在 ngOnInit 中使用 document.querySelectorAll。 我们应该在 ngAfterViewInit 中使用 @ViewChildren。 有点像下面的代码。

      import { ViewChildren, ElementRef, QueryList } from '@angular/core';
      
      
      export class YourComponent {
      
          @ViewChildren('tabledatasMark') tabledatas: QueryList<ElementRef>;
      
          ...
      
          ngAfterViewInit () {
              this.tabledatas.forEach((elem: ElementRef) => {
                  elem.nativeElement.innerHTML = 'HTML code you need';
              });
          }
      
      }
      

      请注意,您的 tabledatas 元素应标有“#tabledatasMark”,即

      <div #tabledatas name="tabledatas">
      ... 
      <div #tabledatas name="tabledatas">
      

      附:让我注意到,使用 InnerHTML 不是一个好主意。

      【讨论】:

      • 我明天试试这个。但是在阅读您的回答后我的第一印象是我有点盲目 :-) 目前,我正在从 AngularJS 转移。这是一个很好的解决方案。但你绝对正确:为什么不使用 ViewChildren...
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-11-03
      • 2020-10-15
      • 2015-09-20
      • 2019-07-04
      • 2011-06-28
      • 1970-01-01
      • 2021-07-20
      相关资源
      最近更新 更多