shadowRoot custom element not rendering content - shadow-dom

First time with custom elements so maybe I'm missing something obvious.
I've got a simple custom element class that I'm inserting HTML into, but it doesn't render on the page. Any clues?
class SearchBar extends HTMLElement{
constructor(){
super();
var shadowRoot = this.attachShadow({mode: "open"});
shadowRoot.innerHTML = `
<input type="text" class="video-input" placeholder="Enter a YouTube URL...">
<style>.video-input{width: 100%; padding: 14px; font-size: 1.3em;color:white;}</style>
`
}
}
window.customElements.define("search-bar", SearchBar);
And the HTML:
<div class="video-container">
<search-bar></search-bar>
</div>

White on white is not a good idea ;-)
Try another color.
class SearchBar extends HTMLElement{
constructor(){
super();
var shadowRoot = this.attachShadow({mode: "open"});
shadowRoot.innerHTML = `
<input type="text" class="video-input" placeholder="Enter a YouTube URL...">
<style>.video-input{width: 100%; padding: 14px; font-size: 1.3em;color:red;}</style>
`
}
}
window.customElements.define("search-bar", SearchBar);
<div class="video-container">
<search-bar></search-bar>
</div>

Related

Angular Material Dialog with Google Places Autocomplete dropdown positioning

I have a web page that uses the Angular framework and therefore the Materials UI library. I have a dialog with a form that uses the Google Places Autocomplete functionality, but the positioning of it stays constant when scrolling through the dialog. Without the dialog, the autocomplete positioning works as I would like and stays directly beneath the input. No styling on the .pac-container has been done for the positioning. The dialog and non-dialog have the same code and styling. Thank you in advance! (Mind the ugliness, it is all testing right now)
google.maps.places.Autocomplete position offset inside angular material Dialog is the exact issue I am having (I think), but I do not know what is meant by "My solution was to remove the top style and then restore it."
Initial position of autocomplete in the dialog
Autocomplete position when scrolling through the dialog
Initial position of autocomplete outside dialog
Autocomplete position when scrolling outside dialog
Non-Dialog TS:
export class AddressTestComponent implements OnInit, AfterViewInit {
#ViewChild("addressLine1") addressField1: ElementRef;
#ViewChild("addressLine2") addressField2: ElementRef;
#ViewChild(MatAutocompleteTrigger, {static: false}) trigger: MatAutocompleteTrigger;
addressForm: UntypedFormGroup;
googleAutocomplete: google.maps.places.Autocomplete;
constructor(private formBuilder: UntypedFormBuilder) { }
ngOnInit(): void {
this.addressForm = this.formBuilder.group(
{
addressLine1: ['', Validators.required],
addressLine2: [''],
city: ['', Validators.required],
state: ['', Validators.required],
zipCode: ['', Validators.required],
country: ['', Validators.required],
}
);
}
ngAfterViewInit(): void {
this.googleAutocomplete = new google.maps.places.Autocomplete(this.addressField1.nativeElement as HTMLInputElement, {
componentRestrictions: { country: ["us"] },
fields: ["address_components"],
types: ["address"]
});
this.addressField1.nativeElement.focus();
this.googleAutocomplete.addListener("place_changed", () => this.autocomplete(this.googleAutocomplete.getPlace()) );
}
}
Non-Dialog HTML:
<div>
<div class="dialog-header">
<h2>Add a New Address</h2>
<h2 class="header-closer" (click)="onClose()" >X</h2>
</div>
<form [formGroup]="addressForm" (ngSubmit)="onSubmitNewAddress()" class="address-form">
<div class="address-wrapper">
<mat-form-field (keydown.escape)="$event.stopPropagation()"
appearance="fill">
<mat-label>Address Line 1</mat-label>
<input matInput #addressLine1 formControlName="addressLine1" required>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Address Line 2 (Optional)</mat-label>
<input matInput #addressLine2 formControlName="addressLine2">
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>City</mat-label>
<input matInput formControlName="city" required>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>State</mat-label>
<input matInput formControlName="state" required>
</mat-form-field>
<mat-form-field appearance="fill" style="margin-bottom: 10px;">
<mat-label>Zip Code</mat-label>
<mat-hint align="end">{{ zipcode.value.length }} / 5</mat-hint>
<input matInput #zipcode type="tel" [maxLength]="5" formControlName="zipCode" required>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Country</mat-label>
<input matInput formControlName="country" required>
</mat-form-field>
</div>
<div class="form-buttons">
<button mat-raised-button (click)="onClose()">Cancel</button>
<button mat-raised-button color="primary" type="submit" [disabled]="this.addressForm.invalid">Use This Address</button>
</div>
</form>
</div>
Non-Dialog SCSS:
.dialog-header {
display: flex;
justify-content: space-between;
align-items: baseline;
margin-bottom: 5px;
}
#map {
height: 100%;
}
.address-form {
padding-bottom: 2000px; // for scrolling test
}
.header-closer {
cursor: pointer;
color: red;
margin-top: 30px;
}
.address-wrapper {
display: flex;
flex-wrap: wrap;
mat-form-field {
margin: 0 15px;
flex: 1;
}
}
.form-buttons {
button {
margin: 0 5px;
}
button:hover {
background-color: #771f1f;
}
}
I have tried the autocomplete without a Material Dialog and it works just as intended and how I would like it to work. I am just trying to replicate that while scrolling through the dialog as well. To fix the issue, I tried to change the position styling of .pac-container but was unsuccessful.
EDIT: I figured out what the other stackoverflow link was talking about. Is there a way the autocomplete styling can be tied to the actual input element rather than the html tag?

Nav Tabs positioned at the bottom of the page with Angular Material

I'm trying to build a tab navigation bar like the example below (copied from Ionic docs) with Angular Material. Each of these tabs will lazy load different pages.
To lazy load pages on each tab, the doc suggests using nav mat-tab-nav-bar component. However, this component presents the tabs bar at the top of the page and I need this bar at the bottom of it.
As in the docs, the mat-tab-group has this attribute called headerPosition that can be used to position the tab bar at the bottom of the page, but it doesn't work on the nav mat-tab-nav-bar component.
Can anyone help me either create a tab that can open pages/components in lazy mode with mat-tab-group or position the nav mat-tab-nav-bar component at the bottom of the page?
Currently my component is:
tabs.page.html
<nav mat-tab-nav-bar headerPosition="below" >
<a mat-tab-link *ngFor="let page of pages" (click)="activePage = page.path" [active]="activePage == page.path"> {{ page.label }} </a>
</nav>
<router-outlet></router-outlet>
tabs.page.ts
// ...
export class TabsPage implements OnInit {
readonly pages = [
{
path: 'page1',
label: 'Page 1',
},
{
path: 'page2',
label: 'Page 2',
},
];
activePage = this.pages[0].path;
constructor() { }
// ...
}
Heres the sample.
.page-container {
background-color: #f8f9fa;
padding: 10px;
width: 90%;
min-width: 378px;
}
.parent-container,
.d-flex {
display: flex;
}
.child-centered,
.m-auto {
/* Magic! */
margin: auto;
max-width: 430px;
min-width: 220px;
}
div#topdiv, div#bottomdiv{
position:fixed;
left: 0px;
width: 100%;
color: #CCC;
}
div#topdiv{top:0px;}
div#bottomdiv {bottom:0px;}
<div class="parent-container">
<div class="child-centered">
<router-outlet>
</router-outlet>
<div style="height: 150px;"> </div>
<footer id="bottomdiv" class="parent-container">
<nav mat-tab-nav-bar class="child-centered mat-tab-group-inverted-header main-nav" >
<a mat-tab-link style="height: 80px; width: 40px;" *ngFor="let link of navLinks"
routerLink="{{ link.location }}" routerLinkActive #rla="routerLinkActive" [active]="rla.isActive">
<div style="padding: 10px;">
<mat-icon class="example-tab-icon">{{ link.icon }}</mat-icon>
<div>{{ link.label }}</div>
</div>
</a>
</nav>
</footer>
</div>
</div>

Angular Material mat-tabs all have different heights

I wish to have all the tabs have the same height, no matter what contents are inside.
The tabs reside inside a div. Preferably I don't need to set a fixed height for this div, but instead the div should have the height of the mat-tab that has the most stuff.
Haven't found anything really works yet, if someone could help that will be wonderful!
My current code:
HTML:
<div fxLayout="column" style="min-height: 100%; height: 100%">
<mat-tab-group style="height: 100%">
<mat-tab label="1">
<mat-card fxFill class="mat-elevation-z4 about-card">
this mat-card contains the most amount of stuff
</mat-card>
</mat-tab>
<mat-tab label="2">
<mat-card fxFill class="mat-elevation-z4 about-card">
...a bunch of things
</mat-card>
</mat-tab>
<mat-tab label="3">
<mat-card fxFill class="mat-elevation-z4 about-card">
...a bunch of things
</mat-card>
</mat-tab>
</mat-tab-group>
</div>
CSS:
.about-card {
display: flex;
align-items: center;
justify-content: center;
margin: 16px;
padding: 16px;
border-radius: 8px;
}
Edit: Some boilerplate example:
First tab:
Second tab:
See how the heights of the content are different
This is a solution using javascript. You need to get the element with the max height and update the height of mat-tab-body-wrapper container :
ngAfterViewInit() {
const groups = document.querySelectorAll("mat-tab-group");
groups.forEach(group => {
const tabCont = group.querySelectorAll("mat-tab-body");
const wrapper = group.querySelector(".mat-tab-body-wrapper")
const maxHeight = Math.max(...Array.from(tabCont).map(body => body.clientHeight));
wrapper.setAttribute("style", `min-height:${maxHeight}px;`);
});
}
You can transform it using the angular API
Try this.
<mat-tab-group #myTabGroup id="myTabGroup">
ngAfterViewInit() {
this.setTabHeights();
}
#HostListener('window:resize', ['$event'])
handleResize(event: Event) {
this.setTabHeights();
}
setTabHeights() {
const tabCardBody = document
.querySelectorAll('mat-tab-group#setupWarehouseDataTab mat-tab-body');
if (!tabCardBody) return;
const maxHeight = Math.max(...Array.from(tabCardBody)
.map((elm: any) => elm.clientHeight));
tabCardBody.forEach((elm => {
elm.setAttribute('style', `height:${maxHeight}px;`);
});
}

How to add a dropdown menu with Logout option using ant d in React typescript

Here is the sample code, i have a avatar and onclick of it i want to show a small dropdown with logout option and possibly username.
import { Avatar, Layout } from 'antd';
<StyledAvatar size="small"> {initials} </StyledAvatar>
const StyledAvatar = styled(Avatar)`
margin-left: ${({ theme }: { theme: Theme }) => theme.paddings.small}px;
color: black;
background-color: white;
font-weight: bold;
`;
<Dropdown
overlay={menu}
trigger={["click"]}
placement="bottomLeft"
>
<div onClick={e => e.preventDefault()}>
<Avatar size="large" icon={<UserOutlined />} />
</div>
</Dropdown>
We put the avatar component inside the Dropdown component.

md-datepicker width is too big

I'm stuck to customize size of md-datepicker! I use it in md-input-container but the size after the picker is shown up ,it takes all my screen size.Below is my code:
<md-input-container flex-xs>
<label>Start Date</label>
<md-datepicker ng-model="leave.start_date"></md-datepicker>
</md-input-container>
Do I need to include any original styles of this datepicker? Thank in advance!
Use the function for manipulate width and hide image of calendar as:
var app = angular.module('StarterApp', ['ngMaterial']);
app.controller('AppController', function($scope) {
$scope.initDatepicker = function(){
angular.element(".md-datepicker-button").each(function(){
var el = this;
var ip = angular.element(el).parent().find("input").bind('click', function(e){
angular.element(el).click();
});
angular.element(this).css('visibility', 'hidden');
});
};
});
CSS
This comes from how the date picker is build behind the scene
.inputdemoBasicUsage .md-datepicker-button {
width: 36px;
}
.inputdemoBasicUsage .md-datepicker-input-container {
margin-left: 2px;
}
.md-datepicker-input-container {
display: block;
}
.md-datepicker-input[placeholder] {
color:red;
}
.padding-top-0 {
padding-top: 0px;
}
.padding-bottom-0 {
padding-bottom: 0px;
}
HTML
<div ng-app="StarterApp" ng-controller="AppController" ng-init="initDatepicker();">
<md-content flex class="padding-top-0 padding-bottom-0" layout="row">
<md-datepicker ng-model="user.submissionDate1" md-placeholder="Start date" flex ng-click="ctrl.openCalendarPane($event)"></md-datepicker>
<md-datepicker ng-model="user.submissionDate2" md-placeholder="Due date" flex></md-datepicker>
</md-content>
</div>

Resources