2017-02-07 41 views
0

我试图运行一些DOM操作代码,当一个observable解决,因此ngIf条件因此在视图中解析,但每次我试图访问它时,它都会返回未定义。这里是我的代码的快照:Angular 2 - ngIf可观察使元素无法访问

查看:

<div *ngIf="data?.data_child" id="data-element"> 
    ... data here 
</div> 

控制器:

public data; 
constructor(private _async: AsyncService){} 

ngOnInit() { 
    this._async.subscribe(result => { 
     if(result) { 
      // data contains data_child 
      this.data = result; 

      // run DOM manipulation on the element 
      if(this.data.data_child) { 

       // error is thrown here as the element is undefined 
       $('#data-element').scrollTop($('#data-element')[0].scrollHeight); 
      } 
     } 
    } 
} 

我想提一提,我曾尝试创建内部ngAfterViewInit另一个订阅,把它那里,但仍,发生同样的错误。

这种工作唯一的事情是当数据加载后发出一个事件,然后我订阅并触发DOM操作方法。但是,它仅在ngOnInit第一次触发时才起作用,因为到该组件的更多路由不再触发事件(没有reuseComponent功能)。

我也尝试使用@ViewChild并设置一个模板变量,然后在控制器中使用,但它仍然抛出相同的错误。

任何想法?谢谢!

+0

您可以使用解析器在模板加载之前获取组件中的所有数据。 –

+0

请您详细说明这个问题,因为我不熟悉它们?在我订阅了用于构建url的activatedRoute参数和queryParameters后,我只能访问我需要获取的数据。在这种情况下,我能够使用解析器吗? –

+1

https://angular.io/docs/ts/latest/api/router/index/Resolve-interface.html google如何使用。但基本上你会做的是把你的请求放在这个类中,在你说你需要在进入组件之前解析解析器的模块中,这样当组件加载数据时就已经存在了。否则,您必须找到解决方法并设置超时时间等。 –

回答

1

使用ngAfterViewInit生命周期钩子来操作DOM元素。你使用jQuery来获取元素的高度吗?您可以使用原生Angular代码执行此操作:this.elementRef.nativeElement.offsetHeight

的jQuery应谨慎使用,但如果你要使用它,你可以让它们使用#data-element作为其选择一个指令:

import { Directive, ElementRef, AfterViewInit } from '@angular/core'; 

declare var $: any 

@Directive({ 
    selector: '#data-element' 
}) 
export class DataElementDirective implements AfterViewInit { 

    constructor(private el: ElementRef) { 
    } 

    ngAfterViewInit() { 
    $(this.el.nativeElement).scrollTop($('#data-element')[0].scrollHeight); 
    } 

} 

但同样应该没有必要诉诸jQuery的这个之类的事情。

+0

我尝试使用elementRef以及ngAfterViewInit内部,但它会引发nativeElement未找到的错误,这是因为那个可观察的和ngIf –

+0

我认为你应该发布Plunkr,我有一种感觉,直接解决您正在尝试解决的问题。 – unitario

+0

感谢您更新您的答案!我很快就会遇到指令,他们似乎很方便。我使用Resolver来解决我的问题。 –

1

您必须为变化检测提供一个机会,先检测某个事物并进行渲染。

当你设置this.data = result;你的变化检测将启动并将命令重新渲染受影响的视图(/ -child)。这将花更长的时间来评估您的下一个if情况,这意味着您目前拨打jQuery功能DOM Element尚无法访问。

一个快速和肮脏的解决办法是使用setTimeout

this.data = result; 

if(this.data.data_child) { 
    setTimeout(() => { 
     $('#data-element').scrollTop($('#data-element')[0].scrollHeight); 
    }); 
} 

你可以在你的榜样使用这个,但我要指出,这还不算是一个很好的做法。

更好的方法可能是使用Observable,它会在您的数据被分配或通过其他种类的逻辑通知您时,例如设置您想滚动到的固定锚点,而不依赖于动态添加元素并滚动到该元素。

另一方面,要模仿像scrollTo,focus等事件,动态生成元素上的模糊通常是棘手的,如果你想以编程方式触发它们并希望以“角度”的方式执行它。说到这一点,作为数据容器的指令可能是另一种很好的方式来实现这样的事情,而不使用超时。

+0

good'ol $ timeout返回。不幸的是,这并没有做到这一点,因为元素仍然没有找到(不确定ngIf何时启用它,但它需要它的时间)。 Observable方法与使用EventEmitter非常相似,我尝试过,但只触发一次。 我试图尽可能地保留所有内容,这就是为什么我远离hacky解决方案(如setTimeout)的原因。该指令的解决方案听起来像它会起作用,但是我从来没有在Angular 2中使用它们。 –