Use of Plain JavaScript ( syntax like getDocumentById) in angular5 project is good coding practice or not , or Should we use ElementRef , TemplateRef , ContainerRef for referring the DOM elements instead of Plain JavaScript.
It's not encouraged to use the DOM element manipulation directly .
This blog explains why it should be avoided
With Angular 6 last update by google they have started moving towards shadow dom and dom hierarchy tree it would help dev community to not worrying about actual dom elements manipulation
Use the framework, don't go direct to the DOM (which is what you mean by "plain JavaScript") unless you have no other choice. (Or don't use a framework at all.)
But note the warning in the ElementRef docs:
Permitting direct access to the DOM can make your application more vulnerable to XSS attacks. Carefully review any use of ElementRef in your code. For more detail, see the Security Guide.
If you can avoid using ElementRef (without going direct to the DOM), that's probably best.
Related
In angular 7 - does core library using shadow dom element to handle isolated scope. what is scene behind the creating components in angular 7 and how isolated scope its working ?
can anyone please help me to understand this ?
In Angular default view Encapsulation technique is emulated, which is provided by encapsualation: viewEncapsulation.Emulated , you don't have to explicitly define this. This emulate Native scoping of styles by adding an attribute containing surrogate id to the Host Element.
If you are using encapsualation: viewEncapsulation.None, this doesn't provide any template or style encapsulation, whatever the styles you define, will be applied globally.
If you are using encapsualation: viewEncapsulation.Native this will use the native Shadow DOM technique, but all the modern browsers does not support this.
As per the document of angular, DOM encapsulation is used for component-specific style inject.
This seems to be the key feature like creating a pseudo element and attaching the styles in the name of it.
MDN-Docs
Angular-Docs
Update
Found this in angular's official repo: style_compiler
need to study deeply though!
In dealing with JS frameworks like AngularJS, Angular, and React, I've observed that directly interacting with the DOM is discouraged, and can often lead to bugs, if you ignore the warnings. When I say "interacting with the DOM" I mean using document.getElementById('myElement') and similar methods to do some manipulation or read values from the document.
My question is essentially Why?. Is this a virtual DOM problem, where React (for example) isn't tracking the actual DOM, and therefore will be caught off guard if you make a change "on your own" without notifying React and subsequently updating the virtual DOM? Would Angular have the same problem in such a case?
If someone has knowledge of only a specific framework, I would be very interested to read the answer to my question even if it is not generalized. Obviously, I'm going to go google this some more, but I didn't see a similar question here yet, so I figured I'd post for posterity. Thanks in advance for any insights!
#HDJEMAI linked to this article which I'll repeat, as it's good advice: https://www.reddit.com/r/javascript/comments/6btma7/whats_so_wrong_with_direct_dom_manipulation/
I'll expand on some of those reasons below:
Modern frameworks like Angular and React are designed to hide the DOM because they want to abstract the DOM away. By using the DOM directly you break the abstraction and make your code brittle to changes introduced in the framework.
There are many reasons to want to abstract-away the DOM, and the Reddit page linked-to mostly focuses on "state management" because your framework (Angular, React, etc) will likely make assumptions about the DOM's state that will be broken if you manipulate the DOM directly, for example:
function this_is_your_code() {
tell_angular_to_make_my_sidebar_500px_wide();
document.getElementById('mysidebar').style.width = 700px;
var sidebar_width = ask_angular_for_sidebar_width();
console.log( sidebar_width ); // will print "500px"
}
Another reason to abstract away the DOM is to ensure your code works with non-traditional DOMs besides the typical web-browser document/window DOM environment, for example "server-side Angular" is a thing, where some of the Angular code runs on the server to pre-render HTML to send to the client to minimize application startup delay or to allow web-browsers without JavaScript to access your webpages, in these situations the normal W3C DOM is no-longer available, but a "fake" DOM is available but it's provided by Angular - and it only works through Angular's abstractions - it won't work if you manipulate document directly, for example:
function this_is_your_code_that_runs_in_nodejs() {
tell_angular_to_make_my_sidebar_500px_wide(); // this works and Angular's built-in abstraction of the DOM makes the appropriate change to the rendered server-side HTML
document.getElementById('mysidebar').style.width = 500px; // fails because `document` is not available
}
Really good answer from #Dai above, I would like to add on top of that. For most cases, you should not manipulate the dom directly. There are cases where you have to and it's the right thing to do.
For example, React and Vue has a concept of ref. Which can be though like an id and gives you the access to the dom node. Let's say you are building a chat application where you fetch old chats when the user scroll to the top and you need to keep the last visible chat in focus.
This kind of situations are there and we need to access the dom. The good practice is to keep such code encapsulated and use the framework way of accessing something instead of reaching out for the document/dom.
I want to know the best way to access global objects and emit some events on these objects in Angular App things like ( window, local storage, document or any other purpose)
and is it right to call it like a JS object or should I stick to the Angular way of doing so?
and if I'm not allowed to manipulate DOM with any other library like jQuery in an angular app?
The most common way is to use services to keep track of objects around the app. Wherever you want to access some data, you simply just inject that corresponding service. You can read more about services here: https://angular.io/tutorial/toh-pt4
When it comes to DOM manipulation, Angular have their own functionalities for communicating with the DOM. For example you can manipulate the DOM using the built in Renderer2. You can also get access to the nativeElement of some element reference. It's not recommended to manually update the DOM with Vanilla JS or jQuery.
Renderer2: https://angular.io/api/core/Renderer2
ElementRef: https://angular.io/api/core/ElementRef
I would advice the following:
Don't access the document object for DOM manipulation or use JQuery. Angular itself provides all the methods required in order to manipulate the DOM. Using Angular and JQuery in conjunction would be an antipattern (IMO).
Here are some tools in Angular which allow you to manipulate the DOM:
Template syntax, For dynamicallly outputting html text
NgClass, For dynamicallly adding strings
*NgIf directive, for conditionally showing certain DOM elements
Renderer2, for Doing all sorts of DOM manipulation.
Things like localstorage and sessionstorage you can directly access from your angular application.
For holding your global data I would advice you to use services which allows components to easily share data between each other.
Of course you could in theory add jQuery or another library for DOM manipulation but this defeats the whole purpose of using Angular in the first place. Since we want to use Angular for creating SPA's application in a relatively easy manner.
In angular unit testing using jasmine, we can test the view (html content) in two ways.
Getting the elements from DebugElement
fixture.debugElement.queryAll(By.css('.tableData.billStatus.text-center'))
Getting the elements from DOM.
fixture.debugElement.nativeElement.querySelectorAll('.tableData.billStatus.text-center')
My question is not related to queryAll vs querySelectorAll. It is DOM vs DebugElement. Because when I use either of them, they give me the correct result most of the time.
This question has some relation to this issue
They give a work around to look through DOM elements as opposed to DebugElement as a work around. So what makes these two differ from each other?
I have looked through several posts for the difference, before making this question. But I did not find anything appropriate to this.
debug element contains references and methods to a component or element whereas native element is a reference to the DOM element.
The Usage of DebugElement vs NativeElement depends on your scenario:
If you are going to run your tests only on the browser, then NativeElement is enough, since the tests will be run on the browser, the DOM will be available for NativeElement to do its operations.
If you are going to run your tests on server or some pipeline where the browser platform is not available, then you should use DebugElement, as it will wrap the native elements of the runtime platform, so that you can do query on non-browser supported platforms too.
All the plugins which are currently supporting angular 2.0 don't seem to support Angular Universal. It shows errors due to the direct DOM access. I want to alter the DOM access code in the angular 2 way. Can anyone suggest the angular 2 way for window, document,queryselector(), querySelectorAll(), document.getElementsByTagname(), getElementsByClassName(), etc.
At first, direct DOM access is discouraged in Angular2. You should prefer using directives like *ngFor and custom structural directives to update the DOM.
You can use one of the methods mentioned in angular 2 / typescript : get hold of an element in the template to get hold of an element and use what the Renderer provides to modify the DOM without breaking Universal.
For structural directives see also
https://angular.io/docs/dart/latest/guide/structural-directives.html
Direct Dom access is discouraged in Angular. Also, you can see comments about using elementRef. elementRef is also discouraged. For elementRef, Angular teams says:"Use this API as the last resort when direct access to DOM is needed.".
You can use renderer2 library. Use this library with elementRef together.