本文介绍了渲染器多个selectRootElement问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用Renderer.selectRootElement从我的组件中获取一些元素,如.

一切正常,除非我只选择一个元素( plnkr )./p>

如您所见,我已经创建了一个组件:

export class ExampleComponent implements OnInit{
    @Input() start: any;
    @Input() end: any;

  constructor(public _renderer:Renderer){

  };

    ngOnChanges(){

    }
    ngOnInit(){
        console.log("NG ON CHAN START DATE",this.start);
        console.log("NG ON INIT END DATE",this.end);
        var container =  this._renderer.selectRootElement('.container');
        console.log(container);
        var inner1 =  this._renderer.selectRootElement('.inner1');
        console.log(inner1);
        var inner2 =  this._renderer.selectRootElement('.inner2');
        console.log(inner2);
    }

}

当我尝试运行此命令时,出现错误:

(但是,在我的应用中,当仅找到第一个容器时,便找不到其他容器了.)

任何想法是从哪里来的?

更新

我发现指令没有被完全调用-只有类container的div被添加到HTML中.

解决方案

请勿使用selectRootElement

其目的不是在组件视图中通过选择器选择随机元素.

只需在 DomRootRenderer中查看它的实现

 selectRootElement(selector: string): Element {
    var el = DOM.querySelector(this._rootRenderer.document, selector);
    if (isBlank(el)) {
      throw new BaseException(`The selector "${selector}" did not match any elements`);
    }
    DOM.clearNodes(el);
    return el;
 }
 

您在那看到有趣的东西吗?它正在删除元素内的节点!为什么会那样做呢?因为它的目的是抓住根元素!那么,哪一个是根元素?这听起来很熟悉吗?

<my-app>
    Loading...
</my-app>

是的!那是根本要素.好的,但是如果我只想获取元素,使用selectRootElement怎么了?它返回没有子元素且视图中没有任何变化的元素!当然,您仍然可以使用它,但是您将破坏它的目的并滥用它,就像人们使用DynamicComponentLoader#loadAsRoot并手动订阅该元素一样. EventEmitter.

好吧,毕竟它的名字selectRootElement几乎说了它的作用,不是吗?

您有两个选择可以在视图中获取元素,还有两个正确的选择.

  • 使用局部变量和@ViewChild

 <div #myElement>...</div>

@ViewChild('myElement') element: ElementRef;

ngAfterViewInit() {
   // Do something with this.element
}
 

  • 创建指令以获取所需元素

 @Directive({
    selector : '.inner1,inner2' // Specify all children
    // or make one generic
    // selector : '.inner'
})
class Children {}

template : `
    <div class="container">
        <div class="inner1"></div>
        <div class="inner2"></div>

        <!-- or one generic
            <div class="inner"></div>
            <div class="inner"></div>
        -->
    </div>
`
class Parent (
    @ViewChildren(Children) children: QueryList<Children>;
    ngAfterViewInit() {
        // Do something with this.children
    }
)
 

I am trying to use Renderer.selectRootElement to get some elements from my Component, as described here.

Everything works fine, unless I select only one element (plnkr).

As you can see, I have created a component:

export class ExampleComponent implements OnInit{
    @Input() start: any;
    @Input() end: any;

  constructor(public _renderer:Renderer){

  };

    ngOnChanges(){

    }
    ngOnInit(){
        console.log("NG ON CHAN START DATE",this.start);
        console.log("NG ON INIT END DATE",this.end);
        var container =  this._renderer.selectRootElement('.container');
        console.log(container);
        var inner1 =  this._renderer.selectRootElement('.inner1');
        console.log(inner1);
        var inner2 =  this._renderer.selectRootElement('.inner2');
        console.log(inner2);
    }

}

When I try to run this, I have an error of :

(however, in my app, when only the first container is found, then none others are found).

Any ideas where does this come from?

UPDATE

I found out that the directive is not invoked fully - only div with class container gets added to the HTML.

解决方案

DO NOT USE selectRootElement

Its purpose is not to select random elements by selector in your components view.

Simply see its implementation in DomRootRenderer

selectRootElement(selector: string): Element {
    var el = DOM.querySelector(this._rootRenderer.document, selector);
    if (isBlank(el)) {
      throw new BaseException(`The selector "${selector}" did not match any elements`);
    }
    DOM.clearNodes(el);
    return el;
 }

Do you see something interesting there? It's removing the nodes inside the element! Why would it do that? Because its purpose it's to grab the root element! So which one is the root element? Does this sound familiar?

<my-app>
    Loading...
</my-app>

Yes! That's the root element. Okay then, but what's wrong with using selectRootElement if I only want to grab the element? It returns the element without its children and nothing changes in the view! Well, you can still use it of course, but you will be defeating its purpose and misusing it just like people do with DynamicComponentLoader#loadAsRoot and subscribing manually to EventEmitter.

Well, after all its name, selectRootElement, says pretty much what it does, doesn't it?

You have two options to grab elements inside your view, and two correct options.

  • Using a local variable and @ViewChild

<div #myElement>...</div>

@ViewChild('myElement') element: ElementRef;

ngAfterViewInit() {
   // Do something with this.element
}

  • Create a directive to grab the element you want

@Directive({
    selector : '.inner1,inner2' // Specify all children
    // or make one generic
    // selector : '.inner'
})
class Children {}

template : `
    <div class="container">
        <div class="inner1"></div>
        <div class="inner2"></div>

        <!-- or one generic
            <div class="inner"></div>
            <div class="inner"></div>
        -->
    </div>
`
class Parent (
    @ViewChildren(Children) children: QueryList<Children>;
    ngAfterViewInit() {
        // Do something with this.children
    }
)

这篇关于渲染器多个selectRootElement问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-12 20:34