Angular flex-layout, grid size not working as expected - angular7

Sorry if this is a really simple problem, just trying to get my head around angular flex grid.
I have this component
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
name = 'Angular';
viewAreas: any[] =
[{
areaName: 'A',
layoutSize: "70",
},
{
areaName: 'B',
layoutSize: "30"
}
];
}
along with this template
<div fxLayout="row">
<div *ngFor="let area of viewAreas" style="border: 2px solid red">
<div [fxFlex.gt-sm]="area.layoutSize"
[fxFlex.gt-xs]="area.layoutSize"
[fxFlex]="area.layoutSize">
{{area.areaName }} {{area.layoutSize }}
</div>
</div>
</div>
I would expect this to give me a row with 2 sections, 1 70% the width of the page and another 30% but I'm not getting that
You can see this here
https://stackblitz.com/edit/angular-umhsx2
If someone could tell me what i'm doing wrong it would be appreciated.

fxLayout="row"
Works only with the direct child be
fxFlex.gt-*
So try the following code.
<div fxLayout="row">
<div *ngFor="let area of viewAreas" style="border: 2px solid red" [fxFlex.gt-sm]="area.layoutSize"
[fxFlex.gt-xs]="area.layoutSize"
[fxFlex]="area.layoutSize">
{{area.areaName }} {{area.layoutSize }}
</div>
</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>

Material navbar isn't opening in responsive mode on handsets

I've created a site using the Angular Material schematic for a navbar which opens a sidebar when in responsive mode. I noticed that when running on the local dev server and using Chrome to emulate a handset it showed the sidenav as expected. Now that I've deployed to UAT and can browse from my phone, the sidenav doesn't show as I expect it to.
Oddly when using Chrome to emulate a phone, when switching it changes but when I reload the page I'm stuck with the sidenav not showing.
Here is my navbar.component.html
<mat-sidenav-container class="sidenav-container">
<mat-sidenav #drawer class="sidenav" fixedInViewport
[attr.role]="(isHandset$ | async) ? 'dialog' : 'navigation'"
[mode]="(isHandset$ | async) ? 'over' : 'side'"
[opened]="(isHandset$ | async) === false">
<mat-toolbar>Menu</mat-toolbar>
<mat-nav-list>
<a mat-list-item *ngFor="let link of navLinks"
routerLink="{{link.link}}" (click)="drawer.toggle()">{{link.label}}</a>
</mat-nav-list>
</mat-sidenav>
<mat-sidenav-content>
<mat-toolbar color="primary">
<button
type="button"
aria-label="Toggle sidenav"
mat-icon-button
(click)="drawer.toggle()"
*ngIf="isHandset$ | async">
<mat-icon aria-label="Side nav toggle icon">menu</mat-icon>
</button>
<span class="md-title">South Island Practice Management</span>
<nav>
<ul>
<li *ngFor="let link of navLinks">
<a routerLink="{{link.link}}" class="navlink">{{link.label}}</a>
</li>
</ul>
</nav>
</mat-toolbar>
<router-outlet></router-outlet>
</mat-sidenav-content>
</mat-sidenav-container>
And here is the navbar.component.ts
import { Component } from '#angular/core';
import { BreakpointObserver, Breakpoints } from '#angular/cdk/layout';
import { Observable } from 'rxjs';
import { map, share } from 'rxjs/operators';
#Component({
selector: 'app-navbar',
templateUrl: './navbar.component.html',
styleUrls: ['./navbar.component.css']
})
export class NavbarComponent {
isHandset$: Observable<boolean> = this.breakpointObserver.observe(Breakpoints.Handset)
.pipe(
map(result => result.matches),
share()
);
constructor(private breakpointObserver: BreakpointObserver) {}
navLinks = [
{
label: 'Home',
link: '/home'
},
{
label: 'About Us',
link: '/aboutus'
},
{
label: 'Our Services',
link: '/services'
},
{
label: 'Contact Us',
link: '/contactus'
},
]
}
The site is currently live at https://sipm-b2ce5.firebaseapp.com
I'm at a bit of a loss having come over from Bootstrap where this sort of behaviour "Just Works™"

How to add css for ion-menu in ionic 4 as there is no app.css is available?

I want to design the ion-menu and implement css in the menu but where we will write the css i am not getting as there is no app.css is available.
I want to add the categories and inside that i want to add sub categories but from the web service. How to do this please help me.
I have tried but i am able to show the menu options static not dynamic which i will get from the api.
Please guide me what to do.
<ion-app>
<ion-menu contentId="content" side="start">
<ion-header>
<ion-toolbar>
<ion-title>Menu</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<div *ngFor="let p of pages">
<ion-menu-toggle *ngIf="p.url">
<ion-item [routerLink]="p.url" routerDirection="root" routerLinkActive="active">
<ion-icon [name]="p.icon" slot="start"></ion-icon>
<ion-label>
{{p.title}}
</ion-label>
</ion-item>
</ion-menu-toggle>
<ion-item button *ngIf="p.children?.length > 0" (click)="p.open = !p.open" [class.parent-active]="p.open"
style="font-weight: 500;" detail="false">
<ion-icon slot="start" name="arrow-forward" *ngIf="!p.open"></ion-icon>
<ion-icon slot="start" name="arrow-down" *ngIf="p.open"></ion-icon>
<ion-label>{{ p.title }}</ion-label>
</ion-item>
<ion-list *ngIf="p.open">
<ion-menu-toggle>
<ion-item *ngFor="let sub of p.children" class="sub-item" style="padding-left: 20px;
font-size: small;" [routerLink]="sub.url" routerDirection="root" routerLinkActive="active"
style="--ion-text-color: var(--ion-color-primary);">
<ion-icon [name]="sub.icon" slot="start"></ion-icon>
<ion-label>
{{ sub.title }}
</ion-label>
</ion-item>
</ion-menu-toggle>
</ion-list>
</div>
</ion-content>
</ion-menu>
<ion-router-outlet [swipeGesture]="false" id="content" main></ion-router-outlet>
</ion-app>
I want the dynamic data to display in the side menu and design the side menu.
app.component.ts
pages = [
{
title: 'Main',
url: '/home',
icon: 'home'
},
{
title: 'Categories',
children: [
{
title: 'categories',
url: '/categories',
icon: 'arrow-dropright'
},
{
title: 'wishlist',
url: '/wishlist',
icon: 'arrow-dropright'
}, {
title: 'Your Orders',
url: '/your-orders',
icon: 'arrow-dropright'
}, {
title: 'My Profile',
url: '/profile',
icon: 'play'
}
]
}, {
title: 'Offers',
children: [
{
title: 'categories',
url: '/categories',
icon: 'play'
},
{
title: 'wishlist',
url: '/wishlist',
icon: 'play'
},
]
}, {
title: 'LogOut',
url: '/user-login',
icon: 'log-out'
}
];
Use style below ion-content
for example this will make your ion-menu background black.Like that do for other elements inside your menu
<style>
ion-content{
background:black;
}
</style>
You can add app.componet.scss in src directory. And you have to add styleUrls to Component decorator like below:
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
encapsulation: ViewEncapsulation.None
})

How to Validate Angular 2 FormArray for length and Regex

app.component.ts
import { Component,OnInit } from '#angular/core';
import {FormControl,FormGroup,FormArray,FormBuilder} from '#angular/forms'
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
name = 'Angular 6';
form=new FormGroup({
topics:new FormArray([])
})
addTopic(topic:HTMLInputElement){
(this.form.get('topics') as FormArray).push(new FormControl(topic.value));
topic.value='';
}
}
app.component.html
<form>
<input type="text" class="form-control" (keyup.enter)="this.addTopic(topic)" #topic />
<ul class="list-group">
<li class="list-group-item" *ngFor="let topic of form.get('topics').controls">
{{topic.value}}
</li>
</ul>
</form>
I have created a Multi Input Control using Angular FormArray but how can i Validate the same for Minimum 2 Items(Length=2) and only accept integer values.
How to Add Validators.minlength like Reactive Form / Model Driven Form Approach.
How can i get those items using ngModel?
I hope this helps.
import {
Component,
OnInit
} from '#angular/core';
import {
FormControl,
FormGroup,
FormArray,
FormBuilder
} from '#angular/forms'
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
name = 'Angular 6';
form = new FormGroup({
topics: new FormArray(this.formBuilder.control(''), [Validators.reqired, Valiadtors.minlength(2)], Validators.Paterrn("^[0-9]*$"))
])
addTopic(topic: HTMLInputElement) {
(this.form.get('topics') as FormArray).push(new FormControl(topic.value));
topic.value = '';
}
}

Resources