Angular elements - Element.createShadowRoot deprecation - javascript

I'm testing Anuglar Elements to create some web components and is working great. Anyways I'm getting this warning in console:
[Deprecation] Element.createShadowRoot is deprecated and will be
removed in M73, around March 2019. Please use Element.attachShadow
instead. See https://www.chromestatus.com/features/4507242028072960
for more details.
Related file is platform-browser.js:1182.
Is something I should be aware of? How can i fix it? Should I search an alternative way to create my web components?

According to MDN Web docs this feature is going to be removed completely. In any case it's not supported by most of the web browsers:
Non-standard
This feature is non-standard and is not on a standards
track. Do not use it on production sites facing the Web: it will not
work for every user. There may also be large incompatibilities between
implementations and the behavior may change in the future.
Deprecated
This feature is no longer recommended. Though some browsers
might still support it, it may have already been removed from the
relevant web standards, may be in the process of being dropped, or may
only be kept for compatibility purposes. Avoid using it, and update
existing code if possible; see the compatibility table at the bottom
of this page to guide your decision. Be aware that this feature may
cease to work at any time.
If you're using Angular i'd suggest using Dynamic Component Loader

As the error states you will have to use
Element.attachShadow instead.
Example:
class SomeElement extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: 'open'});
}
connectedCallback() {
this.shadowRoot.innerHTML = 'Hello World!';
console.log(this.shadowRoot);
}
}
customElements.define('some-element', SomeElement);
The mode defines if you can access the shadow root through JavaScript.
For {mode: 'closed'} the code in the connectedCallback won't work since this.shaodwRoot returns null.

Related

How to tell if a web application is using ReactJs

I know there are tools like Wappalyzer & BuiltWith that give you information about which framework or library is used in a website. But I need some kind of proof regarding if ReactJs is really used in a website.
After some research I found out that commands like typeof React or window.React.version, but these commands don't work all the time.
Any ideas on how to check reactJs is used a web application?
try the below snippet, thanks for the examples for each site listed by rambabusaravanan. See the below link
if(!!window.React ||
!!document.querySelector('[data-reactroot], [data-reactid]'))
console.log('React.js');
if(!!window.angular ||
!!document.querySelector('.ng-binding, [ng-app], [data-ng-app], [ng-controller], [data-ng-controller], [ng-repeat], [data-ng-repeat]') ||
!!document.querySelector('script[src*="angular.js"], script[src*="angular.min.js"]'))
console.log('Angular.js');
if(!!window.Backbone) console.log('Backbone.js');
if(!!window.Ember) console.log('Ember.js');
if(!!window.Vue) console.log('Vue.js');
if(!!window.Meteor) console.log('Meteor.js');
if(!!window.Zepto) console.log('Zepto.js');
if(!!window.jQuery) console.log('jQuery.js');
you can find additional info here link
I had the same problem, and in my case, I found it better to rely on the React Developer Tools.
You can install it in Google Chrome, access the website you want to check, and open the Chrome DevTools.
If the website uses React, the React Developer Tools will include two tabs in the Chrome DevTools:
Otherwise, the React Developer Tools won't include the tabs:
There is an extension in Chrome named 'React Developer Tools' which allows you to inspect the React component hierarchies in the Chrome Developer Tools
https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi
There is also another extension named 'React-detector' as well :)
https://chrome.google.com/webstore/detail/react-detector/jaaklebbenondhkanegppccanebkdjlh
Other answers that involve checking for globals like globalThis.React will work fine if the website uses react via a dedicated script HTML element, but will otherwise face the problem that bundlers like webpack can wrap dependency code inside immediately-invoked-function-expressions or other mechanisms for encapsulating their details and preventing them from unnecessarily bleeding into the global scope. Such encapsulation is very often desirable.
One can try to get around this by testing if DOM elements have properties on them that get set in React contexts, such as _reactRootContainer. Like so:
Array.from(document.querySelectorAll('*'))
.some(e => e._reactRootContainer !== undefined)
A page can have tons of elements, so one can try to optimize based on an assumption that React code will call ReactDOM.createRoot and pass it an element queried via HTML id. Ie. instead of checking all DOM elements, only check those that have an id attribute. Like so:
Array.from(document.querySelectorAll('[id]'))
.some(e => e._reactRootContainer !== undefined)
Be aware that the id-filtering optimization will not always work because the id assumption will not always hold.
Important: Since this method relies on the react DOM already having been created, it should be careful not to be applied until one thinks the react DOM has been created. Once can try to apply techniques like the defer attribute on scripts, or using document.onload, or setTimeout, or a combination of them.
Note that wrapping the nodelist from the query to turn it into an array is probably sub-optimal performance-wise, but I feel that to try to optimize it might be micro-optimizing. A check for the presence of react should probably be saved to a variable and never performed again anyway.
This answer doesn't detect the React 18 CRA apps that I've tried it on.
I can't edit that answer (stack overflow says too many pending edits) but it should also have a check for window.__REACT_DEVTOOLS_GLOBAL_HOOK__.
After adding that check it looks like this:
if(!!window.React ||
!!window.__REACT_DEVTOOLS_GLOBAL_HOOK__ ||
!!document.querySelector('[data-reactroot], [data-reactid]'))
console.log('React.js');
if(!!document.querySelector('script[id=__NEXT_DATA__]'))
console.log('Next.js');
if(!!document.querySelector('[id=___gatsby]'))
console.log('Gatsby.js');
if(!!window.angular ||
!!document.querySelector('.ng-binding, [ng-app], [data-ng-app], [ng-controller], [data-ng-controller], [ng-repeat], [data-ng-repeat]') ||
!!document.querySelector('script[src*="angular.js"], script[src*="angular.min.js"]'))
console.log('Angular.js');
if (!!window.getAllAngularRootElements ||
!!window.ng?.coreTokens?.NgZone)
console.log('Angular 2+');
if(!!window.Backbone) console.log('Backbone.js');
if(!!window.Ember) console.log('Ember.js');
if(!!window.Vue) console.log('Vue.js');
if(!!window.Meteor) console.log('Meteor.js');
if(!!window.Zepto) console.log('Zepto.js');
if(!!window.jQuery) console.log('jQuery.js');

Is it safe to create Custom HTML Tags?

I am reading about a technique wherein you can create custom HTML tags, like so:
<!-- REGISTER CUSTOM ELEMENTS -->
<script type="text/javascript">
var ApplicationContainer = document.registerElement('application-container');
document.body.appendChild(new ApplicationContainer());
</script>
Given there is a variety of browsers & browser-versions out there, I was wondering:
Is it safe to create custom tags yet?
If not, what is the proper work-around?
...I'm just curious, really.
No this is not recommended unless you have some sort of polyfill. It is unsupported in most browsers, see caniuse.
There are a few known polyfills however they do have their setbacks. WebComponents Repository
I wouldn't recommend that. you should be able to implement whatever you need using existing HTML tags. you need to think of your requirements again. do you need a new HTML tag to make it distinctive from existing ones? if yes you can always use data attributes to distinguish it from others. but if you essentially need to create a custom tag, Google developers has a very interesting walk through. hope my answer has been helpful.
According to snuggsi
Web Components ARE ready for production
& Custom Elements v1 has full support for every modern browser
including Internet Explorer 11+ / Edge
It is not immediately clear what you mean by "safe", as that is a rather broad and indefinite term.
#PrisonerZER0 I wouldn't call "Olde browsers" the word "safe". Somewhat of an oxymoron. Even M$ has put IE in a coffin. https://www.microsoft.com/en-us/windowsforbusiness/end-of-ie-support
Us supporting them is only asking for trouble. Thanks for the shout.
I created the snuggsi ใƒ„ (https://github.com/devpunks/snuggsi) library as a suite of conventions over the web components/custom elements native browser spec. My philosophy is you shouldn't need to know node, webpack, babel, etc. Should only need to know basic HTML,CSS,JS to be productive in 2017. The following snippet is a perfect example.
Feel free to reach out on github as it seems like you are up to snuff with modern platform development. We won't need these convoluted front end tools where we are going๐Ÿš€ Feel free to reach out on github so i can help you get started!
<hello-world>
Hello {planet}
</hello-world>
<!-- more info # https://github.com/devpunks/snuggsi -->
<script src=//unpkg.com/snuggsi></script>
<script>
// Element Definition -----------------------------
Element `hello-world`
// Class Description ------------------------------
(class extends HTMLElement {
get planet ()
// "automagic" token binding
{ return 'world ๐ŸŒŽ' }
onclick ()
// "automagic" event registration
{ alert (this) }
})
</script>

Angular Universal and browser feature checks

When developing a web app with jQuery or normal JavaScript, it is commonplace to check for feature availability first. So for example, if I want to use the document.oncopy event, I should first have something like this to ensure my code doesn't break for lesser browsers:
if ("oncopy" in document) {
// Feature is available
}
I'm a bit puzzled about how this would work in Angular2. I could still use the same if I expect to only run in the browser, but I'm specifically told to leave the DOM alone if I want to use Angular Universal and depend on templates or the DomRenderer instead. This allows the page to be pre-rendered on the server and provides a truly impressive performance gain.
But suppose I want a specific div to be invisible if the document.oncopy is unavailable. My understanding is that this is not recommended:
<div *ngIf="hasFeature()">...</div>
and
hasFeature() {
return 'oncopy' in document;
}
because then I'm still manipulating the DOM. Note that my example is about the document.oncopy but I could choose any feature whatsoever that doesn't have universal support.
I tested this using Chris Nwamba's tutorial on Scotch and added the following to the end of his Home template:
<div *ngIf="hasFeature()">Feature is supported</div>
<div *ngIf="!hasFeature()">Feature is NOT supported</div>
Update: Interestingly, it gave different results on different browsers. On Chrome 55, it executed as it would normally and showed the "Feature is supported" message. On IE11, I received the "not supported" message. In both instances the server log shows a EXCEPTION: document is not defined message, but the page still seems perfectly okay.
So what is the correct way to check for browser features if I want to use Angular Universal?
Update:
I also toyed around with using a field in the template and assigning that field from one of the life cycle hooks. ngAfterContentInit seemed like a fine candidate, but also causes an error on the server. It still runs fine in the browser with no weird effects (that I have noticed so far).
There are two ways to approach this:
Do the check only once the server is done rendering and the client is completely initialised (including the replay of user events done by preboot.js).
Return a reasonable default when the page is running on the server and perform the actual check only in the browser.
I started looking at the first option, but none of the Angular2 life cycle events will help with this. In fact, you can clearly see them all executing on the server and only then on the client.
I then started looking for something usable in preboot.js but quickly realised it was more complex than it needed to be.
So onto option 2 I went. It turns out checking for the browser is as easy as importing and checking isBrowser.
import { isBrowser } from "angular2-universal";
#Component({
// All the usual stuff
})
export class MyComponent {
// ...
hasFeature(): boolean {
return isBrowser && 'oncopy' in document;
}
// ...
}
And then use the template as I showed in the question.
To check if you're running on the server, import and use isNode in exactly the same way. There doesn't seem to be an obvious way to distinguish between Node and ASP.NET Core, but perhaps it's best not to write too much code that specific to platform.

Transpiling class based web components with babel

I've a simple web component following the latest web components v1 class syntax, it works great in Chrome and Firefox/Edge (with a polyfill) but I'd like it to run in IE11 so I need to transpile the class. However running it through babel produces code that no longer works in any browser.
Is there any way to generate backwardly compatible web components with the class syntax or is there a preferred way to write web components for maximum compatibility?
Example code -
class TestElement extends HTMLElement {
connectedCallback(){
this.innerHTML = "<div>Testing</div>"
}
}
customElements.define('test-element', TestElement)
Error message when using transpiled code is -
Uncaught TypeError: Failed to construct 'HTMLElement': Please use the 'new' operator, this DOM object constructor cannot be called as a function.
To compile Custom Element classes with Babel, you can use this plugin from Github.
It will use Reflect.construct() instead of new, which is not permitted with HTMLElement objects.
One solution is to use the native-shim available with this polyfill
https://github.com/webcomponents/custom-elements
It's not perfect though, would like to find a cleaner solution.

In what situation would document.open() return null?

I'm trying to understand an intermittent script error that I am seeing in a JavaScript intensive thin-client application running under Internet Explorer 6 and Windows XP. The root cause of the problem is that the following function call returns a null value (however it does succeed without an error):
var doc = targetWindow.document.open("text/html","_replace");
Where targetWindow is a window object.
Neither targetWindow nor targetWindow.document is null and so I'm struggling to understand why this call would return null. My interpretation of the documentation is that this method shouldn't ever return null.
This code has been unchanged and working perfectly for many years - until I understand why this is happening I'm not sure either how I might handle this, or what might have changed to cause this to start happening.
What might cause this function call to return null?
According to the documentation you should be passing "replace", not "_replace". Try this instead:
var doc = targetWindow.document.open("text/html", "replace");
Since you say your code has worked for years, then it is likely that something has changed and the above suggestion may not be the issue. However, it is still worth a try.
Have you changed any js files / libraries you are using in your application lately? Also, are you using any browser plugins within the page? It is possible that a newer version of either of these could be somehow affecting your call to "document.open".
document.open() does not have any parameters by W3C standard. Check out this link: http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-72161170
I recommend you to use W3C documentation instead of Microsoft's one because with W3C you are sure it works on all modern browsers, while Microsoft is well known for adding extensions that, of course, works only in their own products. It's called EEE (Embrace, extend and extinguish).
Simply use document.open() without arguments. There are ways to manipulate user history, but that's called bad programming practice. History is user's private data and web application should not try to manipulate it.

Categories

Resources