Monday, August 26, 2019

Update old version Angular package to avoid Angular CLI error

When downloading angular package from git, running 
ng build
on the project 
or 
ng server 
on the demo app may get an error of 

Angular CLI Errorof "The serve command requires to be run in an Angular project, but a project definition could not be found". The reason of the error is the project was created using an old version of Angular CLI with the file name of .angular-cli.json.


To fix the issue, from the folder of .angular-cli.json, run the below command
ng update --all --force 

Thursday, August 22, 2019

javascript sort method does not change order if the return value is not integer

When calling sort method on array with object element, a compare method is passed as parameter to compare each element.

customComparator: (i1, i2)=>{
let ret = i1[fieldToCompare]<i2[fieldToCompare]; //return ret; //this does not work!!! return ret? -1: 1; }

myArray.sort(customCompaartor);

Many languages allow the compare method to return boolean value or integer value. However, for javascript and typescript, the compare method must return an integer, so 

If the result is negative i1 is sorted before i2.
If the result is positive i2 is sorted before i1.
If the result is 0 no changes are done with the sort order of the two values

If a boolean value is returned, no matter it is true or false, the order of the array will not be changed.

Wednesday, August 21, 2019

Chrome javascript debug tip (For Windows platform)

1. To find a javascript or typescript file in the whole source file tree, use
ctrl+p
or 
ctrl+o
and then type part of the file name

2. To search a particular key word in the whole project's js and html source tree, use
ctrl+ shift + f

3. (less useful) run a command
ctrl + shift + p

4. open javascript debugger
F12

5. check the return value of a method
When breaking in a line of code as 
return callSomeFunction(...);
click step over icon, then the return value will show in the debugger's local panel as below


Tuesday, August 20, 2019

Debug Angular library project's typescript code from root application project

Option 1:

The below steps can be used to debug typescript in Angular library project with Angular 8.*

1. Create Angular app
ng new myappwithlib

2. Create library project
ng generate library ui-uploadfile-lib

3. be sure both library and app project build
ng build ui-uploadfile-lib
ng serve

4. update library project to expose some function from library typescript code
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'lib-ui-uploadfile-lib',
template: `
<p>
Load library: {{this.libraryTitle}}
</p>
`,
styles: []
})
export class UiUploadfileLibComponent implements OnInit {
libraryTitle = "my ibrary title";
constructor() { }
ngOnInit() {
}
}
5. import library module to app module file
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import {UiUploadfileLibModule} from 'ui-uploadfile-lib'
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
UiUploadfileLibModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }

6. (Important) in application's root folder, update angular.json file's application serve setting (not library project's build settings) as below
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"sourceMap": {
"scripts": true,
"styles": true,
"vendor": true
},
"browserTarget": "myappwithlib:build"
},
"configurations": {
"production": {
"browserTarget": "myappwithlib:build:production"
}
}
},
7. start app by executing 
ng serve

In browser's javascript debugger page as shown below. Depends on project settings, the typescript code may also show up in localhost:4200/ng: section, so be sure to search the source tree to try to locate the typescript code.



6. Options 2
If you only need to debug some javascript/typescript code from a third party npm package, and do not need to maintain the code, then there is also another easy and quick way to do so. Just copy the source code from the third party package into the src folder of your angular project, and then search and replace all import statement in your js/ts files so as to import the third party package's classes and modules from the local copy of the source files. 

You can leave the project's package.json as it is, the downloaded package will just be ignored.

Monday, August 19, 2019

Bootstrap grid layout note

1.  The column with definition is automatically inherited from small class to large class, so if col-sm is defined, md, lg and xml will automatically inherit the column size setting
  • .col- (phone - screen width less than 576px)
  • .col-sm- (phone in landscape - screen width equal to or greater than 576px)
  • .col-md- (Tablet - screen width equal to or greater than 768px)
  • .col-lg- (Laptop - screen width equal to or greater than 992px)
  • .col-xl- (Desktop - screen width equal to or greater than 1200px)
2. If row is embedded within col, then the col content will be the first row. and the new row will start from second line. The new row width is the width of the parent column width.
3. row can only contain col as sub items.
4. if more than 12 cols are added in a row, it will wrap to a new line after the first 12 cols
5. col with number will automatically share the row width equally
6. col-auto will take up the remaining width
7. if col is  not defined for col or col-xs, then each column will automatically stacked horizontally.

Tuesday, August 13, 2019

Data binding in Angular

There are several ways to handle data binding in Angular framework:

1. string interpolation
Using {{ }} to include a component property or expression in html markup, Angular will convert the property into a string, and show it in the html page. Note string interpolation only works in normal html text, not in element attribute.
<p>The sum of 1 + 1 is not {{myProperty}}.</p>

2. element property binding
Using [] with an html element attribute name to dynamically binding the html element attribute to a component's property, so that the value is come from the component's property at runtime. For example, in the below example, the image src is set to Angular component's itemImageUrl property's value.

<img [src]="itemImageUrl2"> 

Comparing to this, if the html attribute is not surrounded by [], then it means the attribute value is set to the hardcoded value of the string. For example
<img src="https://www.gstatic.com/webp/gallery3/1.png">    

Angular can recognize [] in the element attribute, so then handle anything included in "" as typescript code.


3. element event binding
Using () to include a html element event name, and set it to value to a method call in quotation mark.
 <button (click)="onButtonClicked()">Delete</button>
If the event takes any event parameter, add $event as parameter in calling method.

4. two way binding with ngModel
NgModel directive attribute depends on FormsModule for Angular template based form handling.

when nModel is used for a standalone control, it allows one way (using [] syntax) or two way binding ([()] syntax) for html input element  Only input element types (Input, select, textarea) or custom element implemented ControlValueAccessor interface can use ngModel for two way binding, as the property is binding to the html element's value property as default.
In addition to binding to ts property, [(ngModel)] can also bind to item or item's property got from ngFor loop.

To use two way binding, must import FormsModule in the app module as below.

import { FormsModule } from '@angular/forms';

imports: [
BrowserModule,
FormsModule
],

Html template file:
<input [(ngModel)]="myname" id="example-ngModel">
Web component ts file:
export class FormComponent implements OnInit {
  myname= 'default name';

Note, when using ngModel for html element inside a form, it requires a name attribute, and ngForm will synchronize the html element with component class, so there is no need to setup oneway or two way binding.

If local reference variable is not assigned to value of 'ngModel', then when passing the local variable as a method parameter to ts code, the type of parameter in ts code is HtmlInputElement. If the local reference variable is assigned to the value of 'ngModel', then the type of the parameter in ts code is NgModel
  <div><input type="text" #local1></div>
  <div><input type="text" ngModel #local2="ngModel"></div>
  <ion-button (click)="onCreateOffer(local1, local2)">

ts code:
  onCreateOffer(l1: HTMLInputElement, l2: NgModel) {
    console.log("create offer place", typeof(l1), typeof(l2) );
  }

5. style binding
A element's style can  bind to a property or method's return value as shown below
<p [ngStyle]="{backgroundColor: getColor()}">servers works!</p>

In component typescript file, getColor method is defined as
getColor() {
return this._color;


6. Conditional style class binding
A element's style class can bind to a class conditionally based on property or method return value as shown below. If getColor() returns 'red', then the online style class will be applied to the button element.
<button [ngClass]="{online:getColor()=='red'}" [disabled]="!allowNewServer" class="btn btn-primary" (click)="onCreateServer()">my button</button>

The style class is defined as 
@Component({
selector: 'app-servers',
templateUrl: './servers.component.html',
styles: [`
.online {
color: pink;
}`]
})


7. local reference passed as template html method parameter
In html template, local reference variable can be used to pass the html element or Angular web component as parameter to method call. The below sample pass html input type and SecondComponent as parameter to a js method.

Note, template reference variable are only visible within the template definition scope, as ngIf, ngFor will create a separate template block, so template reference variables defined within ngIf or ngFor clause are not visible to js code outside of the ngIf or ngFor clause. In this case, ViewChild can be used as an alternative solution.

When reference input element

app component html template:
<input type="text" #local1>
<app-second #local2></app-second>
<button class="btn btn-primary" (click)="onMyClick(local1, local2)">button</button>

app Component typescript:
export class AppComponent {
title = 'local';


onMyClick(l1, l2) {
console.log('on click called');
console.log(l1.value);
console.log(l2.getSecondValue()); //getSecondValue is a method in SecondComponent angular web component
}
}


Second Component typescript:

export class SecondComponent implements OnInit {
constructor() { }
ngOnInit() {
}

getSecondValue(){
return 'value from second component';
}
}

8. @ChildView  
@ChildView can let typescript code directly reference the web components.

@ChildView method parameter must indicate which html element is associated with the typescript variable. The below are two types can be specified by @ViewChild query parameter

Html element: 
Single quotation mark is used around the local reference name when specifying a viewChild variable.

app component html file
<input type="text" class="form-control" #local1>
<app-second #local2></app-second>
<button class="btn btn-primary" (click)="onMyClick(local1, local2)">button</button>
<button class="btn btn-primary" (click)="onClick()">button2</button>

Web component typescript file
export class AppComponent {
@ViewChild('local1', {static: true}) local1;
@ViewChild('local2', {static: true}) local2;

onClick(){
console.log(this.local1 + ', ' + this.local1.nativeElement.value);
console.log(this.local2 + ', ' + this.local2.getSecondValue());
}
}

8.2 web component class name
html file
<input type="text" class="form-control" >
<app-second ></app-second>
<button class="btn btn-primary" (click)="onMyClick(local1, local2)">button</button>
<button class="btn btn-primary" (click)="onClick()">button2</button>

web component file
@ViewChild(SecondComponent, {static: true}) local2;


onClick(){
console.log(this.local2 + ', ' + this.local2.getSecondValue());
}




Saturday, August 10, 2019

Three dot operator (spread operator) in javascript

As the name of 'spread operator' implied, the three dot operator in javascript is mainly used to spread an array object into a list of elements. So that array object can be used in more general cases.

For example, in the below code, the numbers array object can use spread operator to convert it to three separate arguments for calling sum function
function sum(x, y, z) {
  return x + y + z;
}
const numbers = [1, 2, 3];
console.log(sum(...numbers));

Spread operator can also be used to combine elements from an array to form another array object, as shown below
var parts = ['shoulders', 'knees']; 
var lyrics = ['head', ...parts, 'and', 'toes']; 
// lyrics is: ["head", "shoulders", "knees", "and", "toes"]

Similar to above, spread can also be used to copy an array object to another one
var arr = [1, 2, 3];
var arr2 = [...arr]; // like arr.slice()
arr2.push(4); 
//arr2 is [1, 2, 3, 4]

Another use case of spread operator is copying object as shown below
ar obj1 = { foo: 'bar', x: 42 };
var clonedObj = { ...obj1 };
// clonedObj contains { foo: "bar", x: 42 }

Friday, August 9, 2019

Understanding SPA - Single Page Web Application

Traditional web applications (like ASP.NET applications) consist of many html pages, when users navigate from page to page, a new http request is sent to server and the server will send a new html page back to client for rendering. As a result, the web app has to maintain the state information in session data, as each html page loaded in browser does not maintain or inherit any information from previous html page.

The page reloading is bad for user experience and also increases the complex to maintain the application state when crossing different html pages. That is the reason of creating of SPA (single page application).

For Single Page Web Application, there is only one html page is loaded in the entire life of the application life time. So it is just like running a desktop application, so that the state maintained in  application is always valid. The html page is just like an empty container, and when users navigate to different UI pages, it just replaces the content in the empty html page.

Many client side javascript frameworks have been created for this purpose, such as Angular, React, VUE. So that it helps developer to create and manage pages shown on the empty pages. Hybrid framework, such as cordova or Ionic, also use the same SPA approach. Correspondingly, the WebAPI and microservice are applied on server side to just respond to client with the required data for xmlhttpreqeust without returning the whole html page to client.

One challenge to Single Page Application is, for browser, the back and forward button is only applying to page navigation between html pages, as those buttons were created for traditional web apps. However, for single paged application, only one html page is loaded, so developers must use javascript framework to properly manage the navigation history, so that user can still use the back and forward button to navigate between the different UI content as if they are loaded as separate html pages. That is one major reason when javascript framework, like Augular is used for creating SPA applications.  

Authentication for SPA is also different from traditional web app. For SPA, all web resource (like html and script, css files) will be loaded on browser, so there is no point to secure those files. The purpose of user authentication and authorization (for example, with angular Auth Guard) is only needed when SPA web sends requests to backend API services. As a result, although SPA app may include the logic of user authentication and authorization (for example, doing an oAuth or SAML login), the purpose of that is only for getting the app ready to send API requests to backend, so SAP app itself does no need to validate the authentication result, such as checking whether the oauth token will be accepted by backend API service or not, instead it just needs to go through the login process, and get the tokens, and  pass the token with the backend API requests, it is the backend api service's response to actually validate the token and decide whether allow the SPA app to call the backend service API. 

For example, when configuring oauth2 authentication on Azure, both backend API app and frontend SPA app should be registered in Azure AD. However, user will never directly login and authenticate to the backend api app. Instead, the backend API app should expose an API, and define a scope for the exposed API. Also, in the Azure AD registered frontend app, it should add a permission to the exposed API by backend API app registration. Then in the frontend application implementation, configure the frontend app's client id, and authorization url, authorization grant type, token url, so that the SPA app can authenticate the user and get the JWT token. The JWT token should include a claim of backend API scope information, the JWT tocken can be passed in http request's authorization header to the backend API, so backend API can validate the JWT token to decide whether the client request has the required permission.

Thursday, August 8, 2019

Understanding relationship between Ionic and Angular

Angular is a javascript client side framework for creating web application, it has its own web UI components, and manipulates the DOM tree, data binding, dependency injection, and routing for single page web app.

Ionic is a client side framework which targets to different client platforms with a common code base. It can also be used to create native mobile app. Ionic implements its own ion UI web components and style sheet, and Ionic also supports native features like camera, geolocation, etc, through cordova or capacitor bridge.

Previously ionic only works with Angular, however, since Ionic 4.0, developers can create Ionic app just using vanilla (pure) javascript code without Angular. That means Ionic does not depends on Angular, so what is relationship between Ionic and Angular when they are used together?

Actually, when using Ionic and Angular together, ionic will import its ion UI components to Angular, so that Angular framework can use those ionic UI components as if they are regular Angular UI components. In addition, ionic leverages Angular framework and cli to manage the application, data binding, dependency injection, and page routing, so that web developers who are already familiar with Angular framework can use the same knowledge to create and manage the ionic application.