需要加载innerHTML然后运行函数

时间:2018-07-24 19:22:22

标签: javascript html angular asynchronous

我正在尝试在highlight()上调用此ngOnInit,但出现此错误:ERROR TypeError: Cannot read property 'innerHTML' of null

ngOninit中,我有

this.annotationSub = this.annotationService
      .getWordUpdateListenerTwo()
      .subscribe((theHardWords: ComplexWord[]) => {
        this.thewords = [];
        this.theHardWords = theHardWords;
        this.theHardWords.map(word => {
          this.thewords.push(word.word);
          this.wordWithAnnotation.push(word);
        });
      });

this.postsSub = this.postsService
     .getPostUpdateListenerTwo()
     .subscribe((posts: Post[]) => {
            this.posts = posts;
            this.posts.map(post => {
              if (post.id === this.id) {
                 this.postIWant = post.fileText;
              }
            });
    });
    this.highlight(this.thewords); 

这会挑选出帖子,然后显示如下:

我的HTML:

<div id="scrollable">
    {{ postIWant }}
</div>

这是给我带来问题的highlight函数,如果在文档加载按钮后调用此highlight函数,它可以正常工作,但是如果我在{{ 1}}没有足够的时间来填充innerHTML,因此会引发错误。

我尝试使用ngOnInit,但即使这样也没有足够的时间。以下是ngAfterViewInit(): void {}函数。

highlight

如前所述,如果我加载页面并按一个按钮来触发highlight(words) { const high = document.getElementById('scrollable'); const paragraph = high.innerHTML.split(' '); const res = []; paragraph.map(word => { let t = word; if (words.indexOf(word) > -1) { t = '<a class="clickable" style="background-color: yellow; text-decoration: underline;">' + word + '</a>'; } res.push(t); }); high.innerHTML = res.join(' '); const elementsToMakeClickable = document.getElementsByClassName( 'clickable' ); const elementsToMakeClickableArray = Array.from(elementsToMakeClickable); elementsToMakeClickableArray.map(element => { element.addEventListener('click', this.viewAnnotation.bind(this)); }); document.getElementById('btnHighLight').style.visibility = 'visible'; } ,它可以工作,但是我希望它运行该功能并突出显示单词,而无需我点击任何东西。有人有什么想法吗?谢谢!

(我正在使用Angular)。

2 个答案:

答案 0 :(得分:2)

我可以看到您没有正确同步观察对象。我宁愿结合来自annotationServicepostsService的可观察物。然后订阅并执行this.highlight(this.thewords);

以下是示例(在RxJS 6中):

const annotation$ = this.annotationService.getWordUpdateListenerTwo();
const posts$ = this.postsService.getPostUpdateListenerTwo();


annotation$.pipe(combineLatest(posts$, (annotations, posts) => ({annotations, posts}))).subscribe((annotations, posts) => {

 // Do your logic here and after execute highlight()

 this.highlight(thewords);
});

在上面的示例中,我组合了annotation$posts$,这意味着订阅将在最新的可观察对象上执行。然后,我猜测您将执行所需的逻辑,最后可以执行highlight()

但是,上述方法不能确保在合并的可观察完成之前加载scrolable div。要侦听特定DOM元素上的更改,可以使用MutationObserver API并创建可添加到scrollable div中的自定义指令。请参阅以下文章Listening to DOM Changes Using MutationObserver in Angular

您也可以尝试通过ViewChild访问HTML。请在以下stackoverflow问题中查看更多信息:How can I select an element in a component template?

答案 1 :(得分:2)

您的document.getElementById('scrollable');调用返回空值。

这就是为什么您不应该与Angular中的DOM交互的原因。 Angular完全解耦了它,并为您提供了一个与之交互的API。

在解析了组件的ngOnInitInput之后,调用

Outputs。一旦附加了视图模板并且解析了模板变量,就会调用ngAfterViewInit

一旦将组件的标记附加到DOM,Angular中就不会触发生命周期挂钩。

有很多方法可以通过Angular而不是通过DOM查询来获取元素,但是这里没有必要。

只需将其绑定到标记中即可

component.html:

<div id="scrollable">
  <a class="clickable inline-styling-is-bad" style="background-color: yellow; text-decoration: underline;">
    {{ postIWant }} 
  </a>
</div>

如果您需要基于数组的一系列重复元素,这似乎很明显,但是只需使用*ngFor

您的“可观察流”也存在一些问题,但这超出了本主题的范围。