extend custom element web components v1 - web-component

I have a custom Web Component, <app-list> that I'm trying to extend into <calcs-list>.
// app-list.html
<script>
window.customElements.define('app-list',
class AppList extends HTMLElement {
constructor() {
super();
}
}
);
</script>
In calcs-list.html I've got:
<link rel="import" href="app-list.html">
<script>
window.customElements.define('calcs-list',
class CalcsList extends AppList {
constructor() {
super();
console.log('CalcsList constructed');
}
}
);
</script>
However, I get the error
Uncaught ReferenceError: AppList is not defined at calcs-list.html:11
Line 11 references class CalcsList extends AppList {
Both files are siblings of the same folder. I tried using an absolute path when importing app-list.html into calcs-list.html but got the same result.
I also tried importing both components into my main index.html file:
//index.html
<link rel="import" href="/src/components/app-list.html">
<link rel="import" href="/src/components/calcs-list.html">
<app-list></app-list>
<calcs-list></calcs-list>
But experience the same result.
The app-list component works in my application without any issue.
I'm scratching my head on this one and because Web Components are considerably new, there isn't a whole lot of troubleshooting info online, especially with V1 of Web Components.
Thanks!

It's because when you write:
customElements.define('app-list',
class AppList extends HTMLElement {}
);
the class AppList is defined only in in the scope of the define() call. That's why it's not seen when you use it after in the second import file.
Instead, you should first define the class (globally) and then use it in the custom element definition:
// app-list.html
<script>
class AppList extends HTMLElement {
constructor() {
super();
}
}
window.customElements.define('app-list', AppList);
</script>

Thanks to #Supersharp, I re-wrote my custom component declaration as such:
// app-list.html
<script>
class AppList extends HTMLElement { ... }
customElements.define('app-list', AppList);
</script>
And calcs-list.html:
<script>
class CalcsList extends AppList { ... }
customElements.define('calcs-list', CalcsList);
</script>
A note of caution: If you declare a tag within the parent element (the element that's being extended) with an id then this will conflict with the extended element's call to super().
For example:
<template id="app-list">
...
</template>
The way to work around this is to use a JavaScript string literal, as referenced by the Google Developers, and not use an id at all.
<script>
let template = document.createElement('template');
template.innerHTML = `
<style> ... </style>
<div> ... </div>
`;
class AppList extends HTMLElement {
constructor() {
super();
let shadowRoot = this.attachShadow({mode: 'open'}).appendChild(template.content.cloneNode(true));
}
}
</script>

Related

Vaadin + LitElement - styles from `get styles()` not getting applied

I have a trivial LitElement class that I want to style with some internal CSS:
import {LitElement, html, css, customElement, property} from 'lit-element';
#customElement('address-card')
export class AddressCard extends LitElement {
#property()
streetAddress?: string;
#property()
postalCode?: string;
#property()
city?: string;
static get styles() {
return css`
.address { border: 1px dashed gray; }
`;
}
render() {
return html`
<div class="address">
<div>${this.streetAddress}</div>
<div>${this.postalCode} ${this.city}</div>
</div>
`;
// Remove this method to render the contents of this view inside Shadow DOM
createRenderRoot() {
return this;
}
}
The static get styles() method should allow me to add styles to the component, but nothing I add there seems to get applied. Not even a * { ... } selector, which should affect all elements, seems to do anything.
The problem is the createRenderRoot() method. If you disable shadow root, there's no need to encapsulate styles inside the component implementation - you can use global CSS. If you want to encapsulate styles, remove the createRenderRoot override and the static get styles() rules will get applied.

Dynamic CSS loading

i have 2 styles
Style1.scss and Style2.scss
Style1
#import "~bootstrap/dist/css/bootstrap.css";
#import "assets/css/aos/styles.css";
#import "assets/css/aos/aos.css";
#import "assets/css/layout.css";
#import "assets/css/theme-brand-1.css";
some css files and one theme file
Style2
some css files and one theme file like style 1
The theme file is different.
Based on the url param for example http:\\localhost:4000\login?section=x
i need to load style 1 and for other http:\\localhost:4000\login?section=y need to load style2.
Method-1 - not worked
Component
this._activatedRoute.queryParams.subscribe(params => {
this.param1 = params.brand;
switch(params.brand){
case 'x': this.cssUrl = '/src/styles1.scss';
break;
case 'y': this.cssUrl = '/src/styles2.scss';
break;
}
});
Html
<link rel="stylesheet" type="text/html" [href]='sanitizer.bypassSecurityTrustResourceUrl(cssUrl)'>
Create a canonical link dynamically using directive and move the link to head declaration in directive load
Directive
#Directive({
selector: '[appMoveToHead]'
})
export class MoveToHeadDirective implements OnDestroy, OnInit {
constructor(private renderer: Renderer2,
private elRef: ElementRef,
#Inject(DOCUMENT) private document: Document) {
}
ngOnInit(): void {
this.renderer.appendChild(this.document.head, this.elRef.nativeElement);
this.renderer.removeAttribute(this.elRef.nativeElement, 'appmovetohead');
}
ngOnDestroy(): void {
this.renderer.removeChild(this.document.head, this.elRef.nativeElement);
}
}
component.ts
canonicalLink:string;
constructor(private sanitizer: DomSanitizer) { }
//In oninit or when your data is ready, generate canonical link
ngOnInit() {
let canLink = "styles1.scss"; // set style here based on your condition
// You can use pipe for sanitizing but lets do it here
this.canonicalLink = this.sanitizer.bypassSecurityTrustResourceUrl(canLink);
}
component.html
<div *ngIf="canonicalLink">
<link rel="canonical" appMoveToHead [attr.href]="canonicalLink" />
</div>

rollup 'rollup-plugin-postcss' dont inject css into head

I want to create an HTML web component and i need to import CSS file but I want to inject it into my shadow dom. I have some code like below:
import introHTML from './Intro.html';
import introCss from './Intro.css';
class IntroWebComponent extends HTMLElement{
constructor(){
super();
this.defineClassProp();
}
defineClassProp(){
this._shadowRoot = this.attachShadow({ mode: 'open' });
this._html = introHTML
this._element = document.createElement('template');
this._element.innerHTML = this._html;
this._element.append(`<style>${introCss}</style>`)
this._shadowRoot.appendChild(this._element.content.cloneNode(true));
}
}
window.customElements.define('index-intro', IntroWebComponent);
but 'rollup-plugin-postcss' keep injecting css to my main html head and i dont know how to stop it
just config your rollup to stop inject style in your js module:
the default config is:
postcss({
inject: { insertAt: 'top' }
})
you must change it to:
postcss({
inject:false
})

How to use video.js with create-next-app nextjs?

I am trying to use Video.js with create-next-app, and I am not able to load the video.js.css. this is what my component looks like.
import videojs from 'video.js'
import videoStyles from '../node_modules/video.js/dist/video-js.min.css'
export default class VideoPlayer extends React.Component {
componentDidMount() {
// instantiate Video.js
this.player = videojs(this.videoNode, this.props, function onPlayerReady() {
console.log('onPlayerReady', this)
});
}
// destroy player on unmount
componentWillUnmount() {
if (this.player) {
this.player.dispose()
}
}
// wrap the player in a div with a `data-vjs-player` attribute
// so videojs won't create additional wrapper in the DOM
// see https://github.com/videojs/video.js/pull/3856
render() {
return (
<div>
<div data-vjs-player>
<video ref={ node => this.videoNode = node } className="video-js"></video>
</div>
<style jsx>{videoStyles}</style>
</div>
)
}
}
I am using styled-jsx/css loader to load the external css file.
Look at the next.js github example. It should be enough to get you started.

Finding the width of an element when using React?

At which point in a React components life cycle can I get the components css properties which are set in a css file?
I've tried it in the render method and the componentDidMount method and neither assigned the css properties to the component.
export default class HomeArtist extends React.Component {
constructor(props){
super(props);
}
componentDidMount(){
let ImageStore = document.getElementsByClassName('home-artist-display');
console.log("ComponentDidMount: ", ImageStore);
}
render(){
var ImageStyle = {
backgroundImage: "url("+this.props.info.image+")"
};
return (
<div className="home-artist-display" style={ImageStyle}>
<Link to={"artist/" + this.props.info.id}>
<h3 className="home-artist-name">{this.props.info.name}</h3>
</Link>
</div>
)
}
}
I wrote a React library that exposes a size object (with width and height props) to components.
For your use case you could use it like so:
import SizeMe from 'react-sizeme'; // import me!
class HomeArtist extends React.Component {
...
render(){
// Size gets passed in as props!
const { width, height } = this.props.size;
var ImageStyle = {
backgroundImage: "url("+this.props.info.image+")"
};
return (
<div className="home-artist-display" style={ImageStyle}>
<Link to={"artist/" + this.props.info.id}>
<h3 className="home-artist-name">{this.props.info.name}</h3>
</Link>
</div>
)
}
}
// wrap your component export!
export default SizeMe()(HomeArtist);
--
You can find out full details at https://github.com/ctrlplusb/react-sizeme

Resources