Friday, March 20, 2020

CSS style loading order by Angular

Angular provides several ways to specify css styles, as the css style loaded later takes priority over css style loaded before, so it is important to load the css style in proper order.

The test shows the css styles loaded by angular following the below orders:
1. css styles specified in index.html's header section
2. css styles specified in angular.json's styles section
3. css styles specified in component's css file



Friday, February 21, 2020

Technology for building modern web app architecture

Few years ago, MVC is a popular choice when designing web application. Both ASP.Net and JSP have full support for it. Basically in MVC, all logic happen on backend web server, and the process are triggered by client side http requests.

With the mobile devices get more and more popular, the native mobile app cannot reuse the existing backend service implemented in MVC, as native app or single paged mobile web app have different ways to render the view, so the view implementation embedded in tradition MVC does not work anymore.

In addition, handling web session data and refreshing page for each http request cannot provide the best user experience on mobile devices. One solution to solve the issue is moving all MVC related logic from server to client, and client will only send requests to server for retrieving model data. The mobile devices or browsers will download the client app package from server only once when app starts, after that, all logic runs on client side,  as if the app is installed on the device.

Certainly, the app still needs to send http requests to server to get or submit the business data, but server is no longer involved in UI rendering by any means, this separate sthe backend business logic from presentation logic, so the backend services can be reused by all kinds of client apps.

Client frameworks - Angular, Reactive and Vue were created for this purpose to create the single paged web application, correspondingly Ionic, Reactive native were created to create the mobile apps, these client side libraries use javascript and css styles to handle UI rendering, so there is no need to return each html page from server.

On the server side, by removing the UI related logic, the focus is now providing the date to client. RestAPIs, WebAPIs and microservices based on json or xml are used to communicate between client and server services, and between services on server sides. Both asp.net and spring provides good support for this purpose.

The AWS, Azure and Google cloud have become the good places to deploy the container based microservices, so technologies like kubernate and docker also become important for web app developers.


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