5

In Angular2 is there way to get element by it's selector NOT in a template but inside whole DOM?

Vnuuk
  • 6,177
  • 12
  • 40
  • 53
  • http://stackoverflow.com/questions/40759325/how-to-get-dom-elements-by-class-id-selectors-and-properties#40759325 – eko Dec 26 '16 at 14:33

4 Answers4

7

It is not recommended to access the DOM directly in angular2, since your are bypassing the Angular2 renderer

You can use other angular 2 features to do that, for example: adding reference to this element.

Check out this issue, it can help you: How to get dom element in angular 2

Community
  • 1
  • 1
michali
  • 3,230
  • 4
  • 18
  • 20
  • 8
    It's good to know that sort of thing, but over the years and after all the Angular code I've written, I've come to the mindset: if it's simple, readable, works, and can be tested, then there's nothing wrong with it. Angular makes doing some very simple things unbelievably painful, and if a plain ol' JS solution is superior in practicality and fits your need, then use it. After all, Angular is just one tool, it's not the final bible. – Tim Consolazio Dec 27 '16 at 11:36
6

Sure, window.document.querySelector, or window.document.querySelectorAll.

eko
  • 39,722
  • 10
  • 72
  • 98
Tim Consolazio
  • 4,802
  • 2
  • 19
  • 28
  • 4
    Downvote: I don't see how this answer provides an "Angular2-way" as requested by the OP – HammerNL Sep 01 '17 at 07:12
  • i think the angular 2 way is more eadapter to the context, if i use Angular it is obvious that i need to do it the 'TheFrameworkIuse' WAY. – Nacim Idjakirene Sep 06 '17 at 11:30
  • I think that should be left up to the OP, who upvoted the answer. "Obvious" is often more relative than the individual believes. – Tim Consolazio Sep 07 '17 at 12:22
  • @TimConsolazio Questions with only tags referring to angular implies it should be an angular answer – Ian Steffy Mar 28 '18 at 14:12
  • Interesting, I think you shouldn't hesitate to add related information if it assists the OP, which it appeared to. If you like I'll add another tag. – Tim Consolazio Mar 28 '18 at 14:32
1

Today there is an "Angular" way of using the Document to query for Elements:

import { Inject } from '@angular/core';
import { DOCUMENT } from '@angular/common';

class DOMService {
  constructor(@Inject(DOCUMENT) private document) {}

  getElementsByClass(clazz: string): HTMLCollection[] {
    return this.document.getElementsByClassName(clazz);
  }
}

Especially with Server-Side rendering Features for example its not recommended to access window directly (window && window.document..). In case you are also manipulating the Elements you should consider using Angulars Renderer2

In case you just need access to an Element inside your current Component you can use @ViewChild or ElementRef features.

Tim
  • 2,236
  • 1
  • 20
  • 26
0

I'm going to post this as another answer, instead of editing the old one, because IMHO both approaches are useful. But this is most definitely a much more "Angularish" one.

There's two Angularish-2 ways to get a reference to a template DOM element; ElementRef, and ViewChild. There may be more, but these are the two that get mentioned everywhere.

ElementRef is probably best to avoid. Evidently it opens you up to potential XSS attacks. There's all kinds of red "beware" around the docs.

So I settled on something that works really well, that being ViewChild.

My template:

<input #myinput type="text" />

Notice that wonky looking #myInput. It serves as an ID, but not a plain ol' DOM id=''. I assume this gets you around the unique IDs problem, as well as the ugly hack of tagging elements with empty CSS classes in lieu of IDs.

In your code: Note I use ES6 without annotations. but to get the same effect, you would use the @ViewChild annotation. It's well doc'd in TS (not in ES6 at all, it took me quite a while to piece it together).

FYI I had to figure out a clean way to do this because I wanted to implement an RxJS stream to do some debouncing and whatnot.

import { Component, ngOnInit, ViewChild } from '@angular/core';

class HomeComponent {
    constructor( ) {}

    ngOnInit ( ) {
        // .nativeElement console.log's out to what you'd expect.
        var inputBox = this.myInputRef.nativeElement;
        // left this in to demonstrate it works as plain ol' DOM elem,
        // if it didn't, this wouldn't work.
        var source = Rx.Observable.fromEvent(inputBox, 'click');
        ...
    }
}

HomeComponent.annotations = [
    new Component ( {
       templateUrl: './views/home/home.component.html',
       queries: { 'myInputRef': new ViewChild ( 'myinput' ) }
    } )
];
export { HomeComponent }

Works like a charm. About time we had something like this in Angular. JQLite really never cut it.

Tim Consolazio
  • 4,802
  • 2
  • 19
  • 28
  • ViewChild is exactly the same as ElementRef btw – Drenai Jan 27 '18 at 19:47
  • Omg...no it isn't. Not even close (if it was they wouldn't bother with the other). – Tim Consolazio Jan 28 '18 at 22:46
  • Yip, it just a different way of getting the same object. The XSS warning are to do with updating/insererting elements into the DOM directily via nativeElement methods - as Angular does not get to apply it's 'sanitization' operators on the updated elements. It's a bit oversold though, as there are very few times you'd update the DOM with user supplied HTML. The Renderer2 and ViewChild/ViewContent systems are quite limited in many respects. Most npm modules/libraries in Angular access document/window if you have a look at the source – Drenai Jan 29 '18 at 00:09
  • e.g. https://github.com/angular/material2/blob/master/src/cdk/overlay/fullscreen-overlay-container.ts – Drenai Jan 29 '18 at 00:21
  • You'll also notice in that link the use of _methodName for their private methods, which is one of the things we are also not suppose to do (from the styling conventions). Difference between best practice and practicality:-) – Drenai Jan 29 '18 at 01:09