Monday, January 20, 2020

Show dialog with angular material project

The below steps can be used to show dialog in an angular material project.

1. create angular project and add angular material package
ng new myapp
ng add @angular/material

2. add material design dialog module into app's module file app.module.ts

import {MatDialogModule} from '@angular/material';
@NgModule({
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    MatDialogModule
  ],

3.Create dialog body component for displaying
First creating three files in the project as below
mydialog.component.ts
mydialog.componen.html
mydialog.component.css

mydialog.component.ts handles the data communication with dialog, the code is shown below
import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material';
import { ComponentOnInit } from '@angular/core';
@Component({
    selector: 'app-dialog',
    templateUrl: 'mydialog.component.html',
    styleUrls: ['mydialog.component.css']
})
export class MyDialogComponent implements OnInit {
    ngOnInit(): void {
        console.log('dialog opened')
    }
}

mydialog.component.html contains the dialog body
<h2 mat-dialog-title>My dialog title</h2>
<mat-dialog-content>


        <input matInput 
        placeholder="input description"
        >


</mat-dialog-content>


<mat-dialog-actions>
    <button class="mat-raised-button" (click)="close()">Close</button>
</mat-dialog-actions>

mydialog.component.css leaves as empty.

4. update app module file to import dialog component, and add it in entryComponents section
import {MatDialogModule} from '@angular/material';
import { MyDialogComponent } from './mydialog.component';


@NgModule({
@NgModule({
  declarations: [
    AppComponent,
    MyDialogComponent
  ],
  providers: [],
  bootstrap: [AppComponent],
  entryComponents:[MyDialogComponent]
})

Test the project with "ng serve", it should show the default angular page.

5. remove default content from app.component.html and add a html button element to open the dialog
<button mat-button (click)="openDialog()">Open dialog</button>

Update app.component.ts to implement openDialog method as below
import { Component } from '@angular/core';
import {MatDialog, MatDialogConfig} from '@angular/material';
import { MyDialogComponent } from './mydialog.component';

export class AppComponent {
  title = 'myapp';


  constructor(private dialog: MatDialog) {}


  openDialog() {
    const dialogConfig = new MatDialogConfig();
    dialogConfig.disableClose = true;


    this.dialog.open(MyDialogComponent, dialogConfig);
  }
}

Set disableClose to true so users can not close the dialog just by clicking outside of the dialog.

Save and run the project, when clicking the open dialog button, it should show the below dialog. Note the dialog cannot be closed now when clicking close button.

 6. close the dialog
Update mydialog.component.ts with a new close method
import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material';
import { Component, OnInit } from '@angular/core';

export class MyDialogComponent implements OnInit {
    constructor(private dialogRef: MatDialogRef<MyDialogComponent>) {}


    close() {
        this.dialogRef.close('input value from user');
    }
}
Test the project again, the dialog should be able to close.

7. passing data into dialog
MatDialogConfig object can be used to pass input data to dialog. Update mydialog.component.ts to add a new line to pass dialog title in dialogConfig.data object

  openDialog() {
    const dialogConfig = new MatDialogConfig();
    dialogConfig.disableClose = true;


    dialogConfig.data = {title: 'my material style'};
    this.dialog.open(MyDialogComponent, dialogConfig);
  }

Update mydialog component to receive input data:
import { Component, OnInit, Inject } from '@angular/core';

export class MyDialogComponent implements OnInit {
    diaTitle: string;
    constructor(private dialogRef: MatDialogRef<MyDialogComponent>,
                @Inject(MAT_DIALOG_DATA) data) {
          this.diaTitle = data.title;
        }
}

Update mydialog.component.html to use the diaTitle for the dialog title

<h2 mat-dialog-title>{{diaTitle}}</h2>

Test again, the title of  my material style" should show.

8. collecting user input from dialog
First update app module .ts file to include form module
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import {MatDialogModule} from '@angular/material';
import { MyDialogComponent } from './mydialog.component';
import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import {FormsModule} from '@angular/forms';


@NgModule({
  declarations: [
    AppComponent,
    MyDialogComponent
  ],
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    MatDialogModule, 
    FormsModule
  ],

Then update app.component.ts to receive dialog output from afterClosed() method as below

  userInput: string;

  openDialog() {
    const dialogConfig = new MatDialogConfig();
    dialogConfig.autoFocus = true;
    dialogConfig.hasBackdrop = true;
    dialogConfig.disableClose = true;


    dialogConfig.data = {title: 'my material style'};


    const dialogRef = this.dialog.open(MyDialogComponent, dialogConfig);


    dialogRef.afterClosed().subscribe(result => {
      this.userInput = result;
    });
  }

Also update app.component.html to show the user output as below
<div>User input in dialog is: <span style="color: red;">{{userInput}}</span></div>
  
Then use ngModel two way bind to get input from dialog by update mydialog.component.html and mydialog.component.ts

mydialog.component.html
<h2 mat-dialog-title>{{diaTitle}}</h2>
<mat-dialog-content>
        <input matInput [(ngModel)] ="diaInput"
        placeholder="input description"
        >
</mat-dialog-content>
<mat-dialog-actions>
    <button class="mat-raised-button" (click)="close()">Close</button>
</mat-dialog-actions>

mydialog.component.ts
export class MyDialogComponent implements OnInit {
    diaTitle: string;
    diaInput: string;


    constructor(private dialogRef: MatDialogRef<MyDialogComponent>,
                @Inject(MAT_DIALOG_DATA) data) {
            this.diaTitle = data.title;
        }


    ngOnInit(): void {
        console.log('dialog opened')
    }


    close() {
        this.dialogRef.close(this.diaInput);
    }
}


Now testing the dialog, the user input will show after the dialog is closed.

Friday, November 29, 2019

Basic css class selector and tip

CSS Selector

#firstname
select element with id="firstname"

.myclass
select all elements with class="myclass"

p (or any html element tag)
select all <p> elements

AND (conditions without space, comma or any in between)
.class1.class2  
select all elements having both class1 and class2 class attribute
p.class1
select all p elements with class1 attribute

OR (comma separated conditions)
p, div
select all p and all div elements

descendant (space separated conditions)
div p
select all p element inside a <div> elements, child or grand child

direct child (> separated conditions)
div>p
select all p element whose direct parent is div

immediate sibling after
div+p
select p element that is immediately after a div element

general sibling after
div~p
select p element follows a p element, not necessary immediately


CSS debug tip
Chrome debugger provides few useful tools to work on css style.

1. element context menu:
After opening the chrome debugger, you can click on an html element, than then select "inspect" from the context menu, it will scroll to the selected element in Chrome debugger's Element view. From there, right click on the element, and the context menu will allow you to do many operation from chrome debugger, including: 
1. Edit the html element and attribute
2. Force the element state, such as focus, hover, visited, active
3. Set an auto break point when sub element has any change, or element's attribute has any change.

2. Style view menus
The Chrome debugger's style view has 3 menu items that can simplify the css style related debugging. 

:hov menu can be used to toggle the element state
.cls menu can be used to add or remove classes defined for the element
+ menu can be used to define new styles in a temporary css file file called inspector-stylesheet.css