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 :
EXCEPTION: The selector ".inner1" did not match any elements in [{{exampleData.end}} in MainViewComponent@3:65]
(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.
The Renderer class has been marked as deprecated since Angular version 4. This section provides guidance on migrating from this deprecated API to the newer Renderer2 API and what it means for your app.
The Renderer2 allows us to manipulate the DOM elements, without accessing the DOM directly. It provides a layer of abstraction between the DOM element and the component code. Using Renderer2 we can create an element, add a text node to it, append child element using the appendchild method., etc.
Using the Renderer for manipulating the DOM doesn't break server-side rendering or Web Workers (where direct access to the DOM would break). ElementRef is a class that can hold a reference to a DOM element. This is again an abstraction to not break in environments where the browsers DOM isn't actually available.
The Renderer2 class is an abstraction provided by Angular in the form of a service that allows to manipulate elements of your app without having to touch the DOM directly.
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.
<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
}
)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With