Τετάρτη 22 Απριλίου 2020

Angular - Redirect to Component with pop-up Material Dialog






Show Component with MatDialog service as popup



Prerequisites:
@angular/material v8.2.3







1. Redirection Service - TS


...
  constructor(public dialog: MatDialog, private location: PlatformLocation, public translate: TranslateService) {
    this.location.onPopState(() => {
      const length = this.dialog.openDialogs.length;
      if (!this.ignorePop) {
        if (length > 0) {
          this.dialog.openDialogs[length - 1].componentInstance.closePopup();
        }
      } else {
        this.ignorePop = false;
      }
    });
  }

// Method to open component 
  open(title: string, componentType: string, options?: { [key: string]: any }): void {
    let translate = this.translate.instant(title);
    if (translate.includes('[' + title + ']')) {
      translate = title;
    }
    const dialogRef = this.dialog.open(RedirectionDialogComponent, {
      data: { title: translate, component: getComponent(componentType)},
      maxWidth: '90%',
      width: '90%',
      height: 98.5 - this.dialog.openDialogs.length * 1.5 + '%',
      hasBackdrop: false,   
     closeOnNavigation: false,
    });


  }
.......



2. Redirection Dialog Component - TS


export interface DialogData {

  title: string;

  component: Type<any>;

  parameters: { [key: string]: any };
}

@Component({
  selector: 'redirection-dialog',
  templateUrl: './redirection-dialog.component.html',
  styleUrls: ['./redirection-dialog.component.scss']
})
export class RedirectionDialogComponent implements OnInit {

  @ViewChild('contentComponent', { static: true, read: ViewContainerRef }) contentComponent!: ViewContainerRef;

  constructor(
    public dialogRef: MatDialogRef<RedirectionDialogComponent >,
    @Inject(MAT_DIALOG_DATA) public data: DialogData,
    public dialog: MatDialog,
    private componentFactoryResolver: ComponentFactoryResolver,
    private el: ElementRef
  ) {}

  ngOnInit(): void {
    const componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.data.component);
    this.contentComponent.clear();
    const compRef = this.contentComponent.createComponent(componentFactory);
  }
}


3. Redirection Dialog Component - HTML

<div>
    <h1> {{data.title}} </h1>
<mat-dialog-content>
    <div #contentComponent></div>
</mat-dialog-content>
</div>

3.1 Example of use:

In your code:
...
this.redirectionService.open('Your component title', 'YourComponent');
...

Πέμπτη 16 Απριλίου 2020

Angular Material accordion/expansion deletable panels






Panels/Cards in Accordion :



Cards layout (also deletable)
Open first panel:


Open second panel: 




Prerequisites:
@angular/material v8.2.3




1. Component - HTML


         <div *ngIf="banks.length" class="bank-accounts-overview">
                <mat-accordion>
                    <div *ngFor="let bank of banks; let i = index;">
                        <div id="id{{i}}">
                            <mat-expansion-panel hideToggle="true" #xyz>
                                <mat-expansion-panel-header [collapsedHeight]="'12vh'" [expandedHeight]="'12vh'">
                                    <mat-panel-title>
                                        <div class="bank-header-entry">
                                            <div class="bank-entry" fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="2.31vw">
                                                <span>{{bank.bankName}}</span>
                                                <span class="balance">{{bank.totalBalance}} €</span>
                                            </div>
                                        </div>
                                    </mat-panel-title>
                                    <mat-panel-description>
                                        <div style="position:absolute; right:0; margin-right: 10px;">
                                        <button (click)=deleteCard(i) type="button" mat-icon-button matSuffix>
                                            <mat-icon>delete_forever</mat-icon>
                                        </button>
                                        </div>
                                    </mat-panel-description>
                                </mat-expansion-panel-header>
                                <div *ngFor="let account of bank.accounts">
                                    <mat-divider></mat-divider>
                                    <div class="jhi-bank-account-entry" matRipple>
                                        <div class="bank-account-entry" fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="2.70vw">
                                            <mat-icon>arrow_forward</mat-icon>
                                            <span>{{account.accountName}}</span>
                                            <span class="balance">{{account.balance}} € </span>
                                        </div>
                                    </div>
                                </div>

                            </mat-expansion-panel>
                        </div>
                        <br/>
                    </div>
                </mat-accordion>

            </div>




2. Component - TS


@Component({
  selector: 'accounts-overview',
  templateUrl: './accounts-overview.component.html',
  styleUrls: ['./accounts-overview.component.scss']
})
export class AccountsOverviewComponent implements OnInit {
  banks: any[] = [];

  constructor(private renderer: Renderer2) {

    this.banks = [
      {
        bankName: 'Bank 1',
        icon: 'account_box',
        totalBalance: 214000,
        hide: false,
        accounts: [{accountId:'1',bankName:'Bank 1',icon:'account_box',accountName:'Account 1',balance:20000},
          {accountId:'1',bankName:'Bank 1',icon:'account_box',bankLoginId:'idxxx',accountName:'Account 1',balance:432000,iban:'XXXA4RRT5',bic:'Bic',hidden:false}]
      },
      {
        bankName: 'Bank 2',
        icon: 'account_box',
        totalBalance: 1645000,
        hide: false,
        accounts: [{accountId:'1',bankName:'Bank 1',icon:'account_box',accountName:'Account 1',balance:17000},
          {accountId:'1',bankName:'Bank 1',icon:'account_box',bankLoginId:'idxxx',accountName:'Account 1',balance:4.000,iban:'XXXA4RRT5',bic:'Bic',hidden:false}]
      },
      {
        bankName: 'Bank 3',
        icon: 'account_box',
        totalBalance: 145.000,
        hide: false,
        accounts: [{accountId:'1',bankName:'Bank 1',icon:'account_box',accountName:'Account 1',balance:150.000},
          {accountId:'1',bankName:'Bank 1',icon:'account_box',bankLoginId:'idxxx',accountName:'Account 1',balance:12.000,iban:'XXXA4RRT5',bic:'Bic',hidden:false}]
      }
    ];
  }

  ngOnInit(): void {
  }

  deleteCard(id: number): void {
    const parent: HTMLElement | null = document.getElementById('id'+id);
    if (parent !== null) {
      const child = parent.children[0];
      this.renderer.removeChild(parent, child);
    }
  }
}



3. Component - CSS


.bank-header-entry {
  width: 80vw;
}

.bank-accounts-overview {
  padding: 1.5vh;
}

.jhi-bank-account-entry {
  padding-top: 3.9vh;
  padding-bottom: 3.9vh;
  padding-left: 30px;
}

button.mat-raised-button {
  height: 6.25vh;
  font-size: 2.08vh;
  line-height: 2.6vh;
  border-radius: 0;
}

h1 {
  font-size: 2.92vh;
  line-height: 3.64vh;
  text-align: center;
  width: 100%;
}

@media (hover: hover) {
  .jhi-bank-entry:hover,
  .jhi-bank-account-entry:hover {
    background-color: #d2d2d2;
  }
}


.bank-entry {
  width: 100%;
}

.logo {
  width: 5.21vh;
  height: 5.21vh;
}

span {
  font-size: 2.08vh;
  line-height: 2.6vh;
  font-weight: bold;
}

.balance {
  margin-left: auto;
}

.bank-account-entry {
  width: 90%;
}





Τρίτη 14 Απριλίου 2020

QR Code display as image - Fix too long qr codes (an-qrcode)







QR Code display as image :








1. Get an-qrcode in your project


Run "npm install an-qrcode --save"
 Ensure success by looking in package.json for an-qrcode



2. app.module.ts


import { AnQrcodeModule } from 'an-qrcode';
..

@NgModule({....
  imports: [AnQrcodeModule],...




3. QR Component - html

<div>
        <div *ngIf="qrCodeValue">
            <br/>
            <h1>QR code scanning</h1>
            <div fxLayoutAlign="space-evenly center">
                 <qrcode *ngIf="qrCodeValue" id="qr-photo"
                        [level]="1"
                        [qrvalue]="qrCodeValue">
                </qrcode>
            </div>
        </div>
</div>




4. QR Component - TS


import {Component, OnInit} from '@angular/core';

@Component({
  selector: 'qr-comp',
  templateUrl: './qr-comp.component.html',
  styleUrls: ['./qr-comp.component.scss']
})
export class QRComponent implements OnInit {

  qrCodeValue = 'toobigqrCodeValueqrCodeValueqrCodeValueqrCodeValueqrCodeValuetoobigqrCodeValueqrCodeValueqrCodeValueqrCodeValueqrCodeValue';

  // QR code
  supportedTypes: 'url' | 'canvas' | 'img' = 'url';

  constructor() {}

  ngOnInit(): void {}
}

QR Code display as image (ngx-qrcode2)







QR Code display as image :








1. Get ngx-qrcode2 in your project

Run 
npm install ngx-qrcode2 --save

Ensure success by looking in package.json for "ngx-qrcode2"



2. app.module.ts

import { NgxQRCodeModule } from 'ngx-qrcode2';
...

@NgModule({....
  imports: [NgxQRCodeModule],...


3. QR Component - html

<div>
        <div *ngIf="qrCodeValue">
            <br/>
            <h1>QR code scanning</h1>
            <div fxLayoutAlign="space-evenly center">
                <ngx-qrcode *ngIf="qrCodeValue" id="qr-photo"
                            [qrc-element-type]="supportedTypes" [qrc-value]="qrCodeValue">
                </ngx-qrcode>
            </div>
        </div>

</div>



4. QR Component - ts

import {Component, OnInit} from '@angular/core';

@Component({
  selector: 'qr-comp',
  templateUrl: './qr-comp.component.html',
  styleUrls: ['./qr-comp.component.scss']
})
export class QRComponent implements OnInit {

  qrCodeValue = 'qrCodeValueqrCodeValueqrCodeValueqrCodeValueqrCodeValue';

  // QR code
  supportedTypes: 'url' | 'canvas' | 'img' = 'url';

  constructor() {}

  ngOnInit(): void {}
}

Τετάρτη 8 Απριλίου 2020

(Material Tab Group) Custom Expand/Collapse mat-card







Custom Expand/Collapse mat-card (Mat-tab-group case)



After clicking down arrow:


After clicking down arrow again, show 1st screen.




Prerequisites:
@angular/material v8.2.3






1. Container component - html


 <mat-tab-group mat-stretch-tabs [dynamicHeight]="true" [backgroundColor]="'#fff'">

    <mat-tab label="Tab 1">
        Content 1 <br><br><br> some content...
    </mat-tab>
    <mat-tab label="Tab 2">
        <some-component></some-component>
        <jhi-your-card></jhi-your-card>
    </mat-tab>
</mat-tab-group>


2. Card Component - html


<div  [ngStyle]="myCardStyle" class="main-container" style="color: #1f69c0">
    <mat-card>
        <div>

            <div *ngIf="isExpanded" fxLayout="row" fxLayoutAlign="start center">
                <button (click)=collapseCard() type="button" mat-icon-button matSuffix style="color: #1f69c0">
                    <mat-icon>keyboard_arrow_down</mat-icon>
                </button> Close
            </div>

            <div class="some-label">
                Label 1
            </div>
            <div fxLayout="row" fxLayoutAlign="start center" class="margin">
                <div class="comp-stuff" fxFlex="80" style="color: #1f69c0">
                    Component stuff
                </div>
            </div>
            <div *ngIf="!isExpanded" class="bottom-links margin" fxLayout="row" fxLayoutAlign="start end">
                <div fxFlex="53"></div>
                <div fxFlex="47" fxLayoutAlign="end">
                    <button mat-button class="bottom-links full-width">Click Me
                    </button>
                </div>
            </div>

            <div *ngIf="isExpanded" class="bottom-links margin" fxLayout="row" fxLayoutAlign="start end">
                <div fxFlex="53"></div>
                <div fxFlex="47" fxLayoutAlign="end">
                    <button mat-button class="bottom-links full-width">Click Me 1
                    </button>
                </div>
            </div>
            <div *ngIf="isExpanded" class="bottom-links margin" fxLayout="row" fxLayoutAlign="start end">
                <div fxFlex="53"></div>
                <div fxFlex="47" fxLayoutAlign="end">
                    <button mat-button class="bottom-links full-width">Click Me 2
                    </button>
                </div>
            </div>
            <div *ngIf="isExpanded" class="bottom-links margin" fxLayout="row" fxLayoutAlign="start end">
                <div fxFlex="53"></div>
                <div fxFlex="47" fxLayoutAlign="end">
                    <button mat-button class="bottom-links full-width">Click Me 3
                    </button>
                </div>
            </div>
            <div *ngIf="isExpanded" class="bottom-links margin" fxLayout="row" fxLayoutAlign="start end">
                <div fxFlex="53"></div>
                <div fxFlex="47" fxLayoutAlign="end">
                    <button mat-button class="bottom-links full-width">Click Me 4
                    </button>
                </div>
            </div>
        </div>

        <br/>

        <div *ngIf="!isExpanded" fxLayout="row" fxLayoutAlign="center center">
            <button (click)=expandCard() type="button" mat-icon-button matSuffix style="color: #1f69c0">
                <mat-icon>keyboard_arrow_down</mat-icon>
            </button>
        </div>

    </mat-card>
</div>


3. Card component - CSS

.main-container {
  padding: 5px;
  width: 100%;
}

div.card-content {
  overflow: hidden;
}

.full-width {
  width: 100%;
}

.button-margin {
  margin-right: 1.5vh;
}

mat-icon {
  margin-left: 1vw;
  margin-top: 1vw;
  font-size: 2.5vh;
}

mat-card {
  margin-left: 1.5vw;
  background-color: white;
  width: 97%;
  margin-bottom: 11vh;
  padding: 3.5vh;
  overflow: scroll;
}

.free-money-label {
  font-size: 2.08vh;
  color: lightgray;
}

.mat-button {
  background-color: darkgray;
  border-radius: 20px;
}

.jhi-last-transaction-entry {
  padding-top: 1.56vh;
  padding-bottom: 1.56vh;
  margin-bottom: 1.5vh;
  margin-top: 1.5vh;
}

.transactions-button {
  font-size: 2.08vh;
  color: #ea485d;
}

.arrow-button {
  img {
    width: 5vw;
    height: 5vw;
  }
}

.free-money {
  font-size: 4.48vh;
  color: #ea485d;
}

.bottom-links {
  font-size: 2.08vh;
  color: white;
}

.margin {
  margin-bottom: 1.5vh;
}

button {
  overflow-x: visible !important;
}


4. Card Component - TS


import {Component, OnInit} from '@angular/core';

@Component({
  selector: 'jhi-your-card',
  templateUrl: './your-card.component.html',
  styleUrls: ['./your-card.component.scss']
})
export class YourCardComponent implements OnInit {

  public myCardStyle = {};

  isExpanded = false;

  expandedCardStyle = {
    ['position']: 'fixed',
    ['z-index']: '1001',
    ['top']: '0',
    ['margin-top']: '13vh',
    ['left']: '0',
    ['width']: '100%',
    ['height']: '80%',
    ['overflow']: 'scroll'
  };

  constructor() {}

  ngOnInit(): void {}

  expandCard(): void {
    this.myCardStyle = this.expandedCardStyle;
    this.isExpanded = true;
  }

  collapseCard(): void {
    this.myCardStyle = {};
    this.isExpanded = false;
  }
}


Δευτέρα 6 Απριλίου 2020

Custom Expand/Collapse mat-card with ngStyle,CSS







Custom Material Card expand/collapse


After clicking down arrow -->


After clicking down arrow again, show 1st screen.




Prerequisites:
@angular/material v8.2.3




1. Container component - html



<div style="height: 33vh;"  fxLayout="row" fxLayoutAlign="center center">
        <p> Some component....</p>
</div>
<jhi-your-card></jhi-your-card>


2. Card component - html


<div  [ngStyle]="myCardStyle" class="main-container" style="color: #1f69c0">
    <mat-card>
        <div>

            <div *ngIf="isExpanded" fxLayout="row" fxLayoutAlign="start center">
                <button (click)=collapseCard() type="button" mat-icon-button matSuffix style="color: #1f69c0">
                    <mat-icon>keyboard_arrow_down</mat-icon>
                </button> Close
            </div>

            <div class="some-label">
                Label 1
            </div>
            <div fxLayout="row" fxLayoutAlign="start center" class="margin">
                <div class="comp-stuff" fxFlex="80" style="color: #1f69c0">
                    Component stuff
                </div>
            </div>
            <div *ngIf="!isExpanded" class="bottom-links margin" fxLayout="row" fxLayoutAlign="start end">
                <div fxFlex="53"></div>
                <div fxFlex="47" fxLayoutAlign="end">
                    <button mat-button class="bottom-links full-width">Click Me
                    </button>
                </div>
            </div>
        </div>

        <br/>

        <div *ngIf="!isExpanded" fxLayout="row" fxLayoutAlign="center center">
            <button (click)=expandCard() type="button" mat-icon-button matSuffix style="color: #1f69c0">
                <mat-icon>keyboard_arrow_down</mat-icon>
            </button>
        </div>

    </mat-card>
</div>



3. Card component - css 


.main-container {
  padding: 5px;
  display: flex;
  justify-content: center;
  position: absolute;
  width: 100%;
}
.full-width {
  width: 100%;
}
.button-margin {
  margin-right: 1.5vh;
}
mat-icon {
  margin-left: 1vw;
  margin-top: 1vw;
  font-size: 2.5vh;
}
mat-card {
  background-color: white;
  width: 95%;
  margin-bottom: 11vh;
  padding: 3.5vh;
}
.some-label {
  font-size: 2.08vh;
  color: lightgray;
}
.mat-button {
  background-color: darkgray;
  border-radius: 20px;
}
.comp-stuff {
  font-size: 4.48vh;
}
.bottom-links {
  font-size: 2.08vh;
  color: white;
}
.margin {
  margin-bottom: 1.5vh;
}
button {
  overflow-x: hidden !important;
}



4. Card component - ts


import {Component, OnInit} from '@angular/core';

@Component({
  selector: 'jhi-your-card',
  templateUrl: './your-card.component.html',
  styleUrls: ['./your-card.component.scss']
})
export class YourCardComponent implements OnInit {

  public myCardStyle = {};

  isExpanded = false;

  expandedCardStyle = {
    ['position']: 'absolute',
    ['z-index']: '10',
    ['top']: '0',
    ['left']: '0',
    ['width']: '100%',
    ['height']: '90%'
  };

  constructor() {}

  ngOnInit(): void {}

  expandCard(): void {
    this.myCardStyle = this.expandedCardStyle;
    this.isExpanded = true;
  }

  collapseCard(): void {
    this.myCardStyle = {};
    this.isExpanded = false;
  }
}



Κυριακή 5 Απριλίου 2020

Display paginated data chronologically with Angular (infinite scrolling)





  •  Display of data elements by time order. 
  • Scrolling down triggers month change in upper bar.
  • Clicking on a month triggers display of related elements




Prerequisites:

- Your backend should provide paginated data (see here how to)
- @angular/cdk": "~8.2.3" 
- @angular/material v8.2.3







1. Component - html



<div class="element-list " fxLayout="column">
  <div class='month-navigation'>
    <a class='monthView' *ngFor="let monthName of months; let i = index"
       (click)="monthClickAction(i)"  [style.left]="defineMoveToLeft(i)">
      {{monthName}}
    </a>
  </div>

  <cdk-virtual-scroll-viewport mat-list itemSize="60" minBufferPx="240" maxBufferPx="480"
    class="transaction-scrolling-viewport" role="list" (scrolledIndexChange)=scrollIndexChangeAction($event) fxFlex="grow">

<!-- See step 5 -->
  <jhi-element-entry *cdkVirtualFor="let element of elementsToShow"
  [icon]="'grade'" [date]="element.date" [amount]="element.amount"
  [mainText]="element.elementName">
  </jhi-element-entry>

    <div class="load-item" >
      <div class="content">
        <div class="text">Loading elements..</div>
        <mat-progress-bar mode="indeterminate"></mat-progress-bar>
      </div>
    </div>

  </cdk-virtual-scroll-viewport>


</div>



2. Component - ts


import {Component, Input, OnInit, ViewChild} from '@angular/core';
import {FormBuilder} from '@angular/forms';
import {IElement} from '../model/your-element.model';
import {CdkVirtualScrollViewport} from '@angular/cdk/scrolling';
import {YourService} from '../services/yourApp.service';
import {HttpErrorResponse, HttpResponse} from '@angular/common/http';
import {HttpPage} from '../model/page.model';

@Component({
  selector: 'jhi-element-list',
  templateUrl: './element-list.component.html',
  styleUrls: ['./element-list.component.scss']
})
export class ElementListComponent implements OnInit {
  @Input()
  public showMonthBar = true;
// See step 7
  private elements: IElement[] = [];
  public elementsToShow: IElement[] = [];

  // See step 4 for this page model
  private page: HttpPage = {number: 0, size: 40, totalPages: 0, totalElements: 0};

  private readonly curMonth: number;
  private readonly curYear: number;
  private activeYear: number;
  indexOfActiveMonth: number;
  private lastIndex = 0;

  @ViewChild(CdkVirtualScrollViewport, {static: true})
  scrollViewPort!: CdkVirtualScrollViewport;

  months = [
    'january',
    'february',
    'march',
    'april',
    'may'
  ];

  constructor(
    private fb: FormBuilder,
    private yourService: YourService
  ) {
    const date = new Date();

    this.curMonth = date.getMonth();
    this.curYear = date.getFullYear();
    this.activeYear = date.getFullYear();
    this.indexOfActiveMonth = date.getMonth();
  }

  ngOnInit(): void {
    this.getElements(0, false);
  }

  getElements(pageNumber: number, doIncrement: boolean): void {
// See step 6
    this.yourService.getElementsByPageAndSize(pageNumber, this.page.size).subscribe(
      (res: HttpResponse<any>) => {
        if (doIncrement) {
// Your API must return paginated data - see this tutorial
          this.elements = this.elements.concat(res.body._embedded.elementDTOList);
        } else {
          this.elements = res.body._embedded.elementDTOList;
        }

        this.page = res.body.page;
        this.elements = this.elements.sort((t1, t2) => t2.date.getTime() - t1.date.getTime());
        this.elementsToShow = this.elements;
      },
      (error: HttpErrorResponse) => {
        // handle error...
      }
    );
  }

  scrollIndexChangeAction(index: number): void {
    if (this.elements[index] === undefined) return;
    this.updateMonthByIndex(this.elements[index].date.getMonth());
    // Load on down scroll event
    if (
      this.lastIndex < index && this.scrollViewPort.measureScrollOffset('bottom') < 50) {
      this.loadNextElementsBatch();
    }
    this.lastIndex = index;
  }

  monthClickAction(index: number): void {
    let compareYear = this.activeYear;
    if (index === 11) {
      compareYear--;
    }
    if (index === 0) {
      compareYear++;
    }

    if (compareYear === this.curYear && index > this.curMonth) return;

    const viewportIndex = this.elements.findIndex(el => el.date.getMonth() === index);
    if (viewportIndex === -1) {
      this.loadNextElementsBatch();
      return;
    }

    this.scrollViewPort.scrollToIndex(viewportIndex, 'smooth');
  }

  updateMonthByIndex(index: number): void {
    if (index === 11 && this.indexOfActiveMonth === 0) {
      this.activeYear--;
    }
    if (index === 0 && this.indexOfActiveMonth === 11) {
      this.activeYear++;
    }
    this.indexOfActiveMonth = index;
  }

  loadNextElementsBatch(): void {
    this.scrollViewPort.checkViewportSize();

    setTimeout(() => this.scrollViewPort.scrollTo({bottom: 0, behavior: 'smooth'}), 25);
    this.getElements(this.page.number + 1, true);
  }

  defineMoveToLeft(index: number): string {
    if (this.indexOfActiveMonth === 0 && index === this.months.length - 1) {
      return '0';
    }
    if (this.indexOfActiveMonth === this.months.length - 1 && index === 0) {
      return '66%';
    }
    if (this.indexOfActiveMonth === undefined) {
      return 33 * index + '%';
    }
    return 33 * (index - this.indexOfActiveMonth + 1) + '%';
  }

}




3. Component - scss



.element-list {

  padding-left: 15px;
  padding-right: 15px;
  height: 98%;
  width: 100%;

  .month-navigation {
    width: 100%;
    position: relative;
    height: 4.8vh;
    margin: 2vh 0;
    overflow: hidden;

    .monthView {
      display: block;
      position: absolute;
      left: 33%;
      transition: 0.2s ease-in-out left;
      top: 0;
      text-align: center;
      line-height: 3.5vh;
      font-size: 1.7vh;
      width: 33%;
      color: #aaa;

      &.active {
        color: #000;
      }
      &.active:after {
        content: '';
        display: block;
        margin: 0 auto;
        width: 50%;
        border-bottom: 0.3vh solid #000;
      }
    }
  }

  mat-form-field.mat-form-field {
    display: block;
    font-size: 2.08vh;
    line-height: 2.6vh;
  }

  .transaction-scrolling-viewport {
    height: 100%;
    width: 100%;
  }

  .load-item {
    width: 98%;

    &.bordered {
      border-bottom: 1px solid #aaa;
    }

    .content {
      width: 80%;
      margin: 1.5vh 10%;
      .text {
        color: #aaa;
        font-size: 1.6vh;
        text-align: center;
        line-height: 2.5vh;
      }
    }
  }

}




4. Model.ts for page property


  export interface HttpPage {
    size: number;
    totalElements: number;
    totalPages: number;
    number: number;
  }



5. Create inner/entry element

Create/adjust yourself this component with date,amount and mainText @input fields, or see this tutorial (coming soon)



6. Create a service method to get paginated data

  
getElementsByPageAndSize(page: number, size: number): Observable<HttpResponse<IElement[]>> {
    let params = new HttpParams();
    httpParams = httpParams .append('page', page.toString());
    httpParams = httpParams .append('size', size.toString());
    return this.http.get<IElement[]>(YOUR_SERVER_API_URL + 'api/your/elements', {
      params: httpParams ,
      observe: 'response'
    });
  }


7. IElement model

export interface IElement {
  elementName: string;
  amount: number;
  date: Date;
}

Τετάρτη 1 Απριλίου 2020

HTML blueprint for Angular Flex Layout / Material





Kick-off blueprint for HTML/CSS design with Angular Flex Layout and Angular Material





Prerequisites:

@angular/flex-layout v9.0.0
@angular/material v8.2.3
   


1. HTML

<div class="wrap-container">
<div class="main-container" fxLayout="column" fxLayoutAlign="space-between center" fxLayoutGap="25vh"> <div style="width:100%;"> <div class="money-label"> Account balance </div> <div fxLayout="row" fxLayoutAlign="start center" class="margin"> <div class="free-money" fxFlex="80"> + 11.500 Euro </div> <div fxFlex="20" fxLayoutAlign="end"> <mat-icon>check_circle</mat-icon> </div> </div> <div class="bottom-links margin" fxLayout="row" fxLayoutAlign="start end"> <div fxFlex="47"> <button mat-button class="bottom-links full-width">Analysis</button> </div> <div fxFlex="6"></div> <div fxFlex="47" fxLayoutAlign="end"> <button mat-button class="bottom-links full-width">Profile</button> </div> </div> </div> <div class="transaction-entry"> <div fxLayout="row" fxLayoutAlign="start center" class="margin-top"> <div class="top-body" fxFlex="80"> Mo. | 16.5.2020 | 12:30 </div> </div> <div class="bottom-body" fxLayout="row" fxLayoutAlign="start end"> <div fxFlex="80"> Transaction #1: </div> <div fxFlex="20" fxLayoutAlign="end"> - 38,00 </div> </div> </div> <div style="width:100%;text-align: center"> <button mat-button class="bottom-links full-width">Submit</button> </div> </div> </div>
2. CSS
.wrap-container {
height: 100%; } .main-container { padding: 20px; } .full-width { width: 100%; } .button-margin { margin-right: 1.5vh; } mat-card { background-color: white; height: 100%; width: 100%; padding: 13.5vh; } .money-label { font-size: 2.08vh; color: lightgray; } .mat-button { background-color: orangered; } .free-money { font-size: 4.48vh; } .bottom-links { font-size: 2.08vh; color: white; } .margin { margin-bottom: 1.5vh; } button { overflow-x: hidden !important; } .transaction-entry { width: 100%; } .top-body { font-size: 2.08vh; color: lightgray; } .margin-top { margin-bottom: 0.5vh; } .bottom-body { font-size: 2.08vh; font-weight: bold; }