Monday, November 4, 2019

Angular Template and Reactive based form input handling

It is a general requirement to access and manage html input element from Angular component typescript code. In simple use case, the html input element can be accessed from typescript code by passing local reference variable from html to typescript as js method parameter, the parameter type is HtmlInputElement.

However, for more complex use case, it is quite often to access the input element as Angular FormControl object. Angular provides both Template based form handling and Reactive based form handling for this purpose. A single component can have both template and reactive based form handling for its html input elements. Angular form classes of FormControl, FormGroup and FormArray are shared by both template and reactive driven forms, they are just created and managed in different ways.

In template based approach, if an input element within a form element has [(ngModel)] directive defined, then angular will automatically creates the FormControl instance, which is transparent from developer's. Within a form, the name attribute of html input element is used to associate the html element to the FormControl instance within NgForm. Usually, the FormControl or NgForm objects are passed as javascript local reference variable parameter to Typescript code, however, they can also be accessed directly from typescript code by using ViewChild for simple use case. Here, the data flow is between the html element and data model defined in ts code and specified by noModel and name attribute, FormControl works internally without developers' explicit access.

In reactive based approach, if an input element has formControl directive defined, or within a FormGroup or FormArray element, then developer can write code to creates the FormControl instance and manage how the html element (based on formControlName or FormControl attribute) is associated with typescript instance, so it let developers directly control the FormControl object without passing it as local reference variable js parameter. This provides more flexible for supporting complex custom validation, so usually, reactive based approach is your best choice.

Note FormControl is a generic type, and is used to represent all types of html input controls. It is html code decides what html input element type is rendered for the formControl. FormControl's construct only takes parameters of initial input text value, and validation method. FormGroup and FormArray are helper collection type to manage FormControl. FormGroup manages its element based on control's name, FormArray manages its elements based on index, basically, the index is used as the name of the control.

When using reactive based form, the module file should import ReactiveFormsModule from "Angular/forms". When using form template based form, the module file should import FormsModule from angular/forms.
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
@NgModule({
  imports: [
    CommonModule,
    FormsModule,
ReactiveFormsModule,
    IonicModule,
    AuthPageRoutingModule
  ],

Angular reactive based form handling

For Angular reactive based form handle, you define and create the FormControl instances in the ts code by yourself and do not rely on angular to automatically generate them for you

1. FormControl
Reactive based form uses FormControl to connect html input element with ts FormControl object, the html input element's FormControl directive attribute's name is used to associate with the ts FormControl property with the same name "myReactFormControl".

Html code
      <mat-form-field>
        Reactive form control test
        <input type="text" matInput [formControl]="myReactFormControl"><br>
      </mat-form-field>    
       Output: <span style="color: blue;">{{myReactFormControl.value}}</span>
      <br>
   
TS code
export class AppComponent implements OnInit {
  // form control
  myReactFormControl = new FormControl('');
myFractFromControl.value contains the current value of the input. User has the full control to which input html elements should be mapped to the ts objects.
2. FormGroup  (optional)
Form group are optional and not necessary to use reactive based FormControl functions. They are only for simplifying the logic by grouping controls together, so multiple FormControl instances are wrapped in a single FormGroup instance. However, a standalone FormControl without FormGroup and Form works in the same way.

The html FormGroup attribute is used to associate with the matched FormGroup property with the same name in component's ts file. The individual input html elements contained in parent FormGroup element use the FormControlName attribute to associate with typescript dictionary object based on the key of the controls

Html file
<div [formGroup]="myFormGroup">
        <div>
          <label for="username">Username</label>
          <input type="text" id="username" formControlName="username">
        </div>
        <div>
          <label for="email">email</label>
          <input type="text" id="email" formControlName="email">
        </div>
        <button mat-button (click)="groupButtonClicked()">Click Me</button> <br>
      </div>

TS file
  myFormGroup: FormGroup;
  constructor(private formBuilder: FormBuilder, private dialog: MatDialog) {}
  ngOnInit() {
     this.myFormGroup = new FormGroup({
      username: new FormControl(''),
      email: new FormControl('')
    });
  }

FormGroup can also contains sub FormGroup or FormArray, in that case, the html side needs to use fromGroupName or FormArrayName attribute to indicate both the name and type information. On typescript side, the typescript object must match both the name and type (FormControl, FormArray, or FormGroup) to associate the html object with the right typescript object.

For sub items within a FormArray, on typescript side, they are hold in a ArrayForm, so no name is set explicitly for each sub item, the item will use the array index as its implicit name. However, the name attribute still needs to be set explicitly on html side, each sub item needs to use FormControlName, FormGroupName or FormArrayName attribute to indicate the type of the sub item, and the value of this name attribute must be a integer, so it can be mapped to a particular element in the array based on the index.

2. For validation, reactive based form only needs to set validation rules in the second parameter of FormControl. The validation state can be retrieved by FormGroup.get('controlName') method
export class ReactFormComponent implements OnInit {
  myForm: FormGroup;
  constructor() { }
  ngOnInit() {
     this.myForm = new FormGroup ({
      username: new FormControl(null, Validators.required),
      email: new FormControl(null, [Validators.required, Validators.email])
    });
  }
The validation output can be accessed from FormGroup's property binding variable.
        <form [formGroup]="myForm" (ngSubmit)="onSubmit()">
          <div class="form-group">
            <label for="username">Username</label>
            <input
              type="text"
              id="username"
              formControlName="username"
              class="form-control" required>
            <span style="color: red;" *ngIf="!myForm.get('username').valid && myForm.get('username').touched">
              user name field is invalid.
            </span>
          </div>
          <div class="form-group">
            <label for="email">email</label>
            <input
              type="text"
              id="email"
              formControlName="email"
              class="form-control">
              <span style="color: red;" *ngIf="!myForm.get('email').valid && myForm.get('email').touched">
                  email field is invalid.
              </span>
          </div>

3. update value from ts file
Similar to template based form handling, FormControl.setValue can be called to replace value for FormControl or FormGroup. patchValue can be used to set a value for a single item.

Angular template based form handling

When angular FormModule is imported, html form element is automatically associated to a NgForm instance, there is no need to add NgForm in your code, and you can access the ngForm instance using the local reference variable. Any input elements inside the Form and with the NgModel attribute will automatically be included in the NgForm.controls property for ts code to access.

1. html input element without a form
<div>input 1: <input type="text" ngModel #input1="ngModel"></div><br>
<div>input 2: <input type="text" #input2></div><br>
<div><button (click)="onsubmit(input1, input2)">submit</button></div>

Typescript code
onsubmit(in1: HTMLInputElement, in2: HTMLInputElement) {
console.log('submit clicked', in1, in2);
const s = in1.value;
}

2. When clicking button whose type is 'submit', the submit event can be handled by form's ngSubmit event binding.
    <form (ngSubmit)="onSubmit()" #f="ngForm">
        <div id="user-data">
          <div class="form-group">
            <label for="lastname">Username</label>
            <input type="text" id="lastname" class="form-control" ngModel name="lastname" required>
            <input type="text" id="firstname" class="form-control" name="firstname" required>
          </div>
        <button class="btn btn-primary" type="submit">Submit</button>
      </form>

3. To access the form data, a local reference can be assigned to value of "ngForm" in form template, and then define a viewChild varible associated with the local reference name to access the form data in its value field.
export class FormComponent implements OnInit {
  @ViewChild('f', {static: false}) view: NgForm;
  constructor() { }
  ngOnInit() {
  }
  onSubmit() {
    console.log('onsubmited clicked, ', this.view);
  }
}

4. For any input html elements within form, in order to include itself in ngForm's controls and value property, the element should add ngModel directive attribute, as well as a name attribute. Internally, Angular creates a FormControl object for each input html element and associating the each pair based on name attribute
    <form (ngSubmit)="onSubmit()" #f="ngForm">
        <div id="user-data">
          <div class="form-group">
            <label for="lastname">Username</label>
            <input type="text" ngModel name="lastname" required>
            <input type="text"  ngModel name="firstname" required>
          </div>
        <button type="submit">Submit</button>
      </form>

5. Using ViewChild local reference variable
In html element, set a local reference variable name to "ngModel" will enable the ts code to access the NgModel variable of this html element
   <form (ngSubmit)="onSubmit()" #f="ngForm">
        <div id="user-data">
          <div class="form-group">
            <label for="lastname">Username</label>
            <input type="text" id="lastname" class="form-control" ngModel name="lastname" required>
            <input type="text" id="firstname" class="form-control" ngModel name="firstname" 
required #first="ngModel">
            first name is {{firstNameValue.value}}
          </div>

ts code
export class FormComponent implements OnInit {
  @ViewChild('f') view;
  @ViewChild('first') firstNameValue;

6. Two way bind using noModel
in html element, ngModel attribute can be used to associate with a ts property for two way binding using [(ngModel)] or one way binding (from ts property to html element) using [ngModel].
 <form (ngSubmit)="onSubmit()" #f="ngForm">
        <div id="user-data">
          <div class="form-group">
            <label for="lastname">Username</label>
            <input type="text" id="lastname" class="form-control" ngModel name="lastname" required>
            <input type="text" id="middlename" class="form-control" [(ngModel)]="middleNameValue" 
name="middlename" required >
            middle name is {{middleNameValue}}
            <input type="text" id="firstname" class="form-control" ngModel name="firstname" required #first="ngModel">
            first name is {{firstNameValue.value}}
          </div>

ts code
export class FormComponent implements OnInit {
  @ViewChild('f', {static: false}) view;
  @ViewChild('first', {static: true}) firstNameValue;
  middleNameValue = 'default Midname';

Actually any html input element'value can be directly accessed from ts code with ngModel two way binding, without the need to add the input element in a parent form element.

7. Client side html and ts code validation
Several build-in validation rules are supported by Angular, the detailed information is available at

On the html code, first set the validation rule on the html element
  <form (ngSubmit)="onSubmit()" #f="ngForm">
        <div id="user-data">
          <div class="form-group">
            <label for="lastname">Username</label>
            <input type="text" id="lastname" class="form-control" ngModel name="lastname" required minlength="5" #lre="ngModel">
            <span class="help-block" style="color:red" *ngIf="lre.errors && lre.errors.required">lastname is required<br></span>
            <span class="help-block" style="color:red" *ngIf="lre.errors && lre.errors.minlength">lastname is min length is 5<br></span>

Then the validation result can be accessed on the html side with local reference variable by ngif as show above.

The validation result can also be accessed on the ts code with the ViewChild variable as shown below
export class FormComponent implements OnInit {
  @ViewChild('lre', {static: true})  lastName: ngModel;
  
  onSubmit() {
    console.log('last name reference variable', this.lastName, this.lastName.errors);
  } 
}

Two way binding is not required for client validation, it only uses local reference variable.

8. Group input elements for better json output
By default, all input elements will have their values included in json object's name-value pair. In order to better organize the json output, the input elements can be organized using  Several build-in validation rules are supported by Angular, the detailed information is available at ngModelGroup attribute. All elements included in a ngModelGroup will be wrapped into a sub object in the output json, the name of the sub object is the name of the ngModelGroup

For example, with the below form
      <form (ngSubmit)="onSubmit()" #f="ngForm">
        <div id="user-data" ngModelGroup="userData">
          <div class="form-group">
            <label for="lastname">Username</label>
            <input type="text" id="lastname" class="form-control" ngModel name="lastname" required minlength="5" #lre="ngModel">
            <input type="text" id="middlename" class="form-control" [(ngModel)]="middleNameValue" name="middlename" required #middleNameRef>
            <input type="text" id="firstname" class="form-control" ngModel name="firstname" required #first="ngModel">
          </div>
          <div class="form-group">
            <label for="email">email address:</label>
            <input type="email" id="email" class="form-control" ngModel name="email" required email #emaillocalref="ngModel">
            <div class="radio" *ngFor="let gender of genders">
              <label>
                <input type="radio" name="gender" ngModel [value]="gender">{{gender}}
              </label>
            </div>
          </div>
        </div>
        <div class="form-group">
          <label for="secret">Secret Questions</label>
          <select id="secret" class="form-control" ngModel name="secret">
            <option value="pet">Your first Pet?</option>
            <option value="teacher">Your first teacher?</option>
          </select>
        </div>
        <button class="btn btn-primary" type="submit">Submit</button>
      </form>

when clicking submit button, the form's json value is in a flat structure as

"{
"lastname":"",
"middlename":"default Midname",
"firstname":"",
"email":"",
"secret":"",
"gender":""
}"

Now we group the lastname, firstname and middlename in a model group as below, and give the group name as "username"
  <form (ngSubmit)="onSubmit()" #f="ngForm">
        <div id="user-data" >
          <div class="form-group" ngModelGroup="username">
            <label for="lastname">Username</label>
            <input type="text" id="lastname" class="form-control" ngModel name="lastname" required minlength="5" #lre="ngModel">
            <span class="help-block" style="color:red" *ngIf="lre.errors && lre.errors.required">lastname is required<br></span>
            <span class="help-block" style="color:red" *ngIf="lre.errors && lre.errors.minlength">lastname is min length is 5<br></span>            
            <input type="text" id="middlename" class="form-control" [(ngModel)]="middleNameValue" name="middlename" required #middleNameRef>
            <input type="text" id="firstname" class="form-control" ngModel name="firstname" required #first="ngModel">
            first name is: {{firstNameValue.value}}, middle name is: {{middleNameValue}}
          </div>
          <button class="btn btn-default" style="background-color: lightgray" type="button" (click)="suggestUserName()">
<span aria-label='Enter search text'>Suggest an Username</span></button>
          <hr>

Then the form's json value is organized as below
"{
   "username":         {"lastname":"laste","middlename":"mid","firstname":"first"},
   "email":"",
    "secret":"",
    "gender":""
}"

9. set form value from ts code
For setting values for all items in the form, call ngForm.setValue() method, and provide form's full json string as parameter.
   setFormData() {
    this.view.setValue({
      username:
        {
          lastname: 'mylast',
          middlename: 'mymid',
          firstname: 'myfirst'
        },
      email: 'myemail@gmail.com',
      secret: '',
      gender: 'female'
   });
  }

For setting a single value of the form, call ngForm.form.patchValue method method, and only provide the json value for that particular html item. The below is an example that only updates user's last name.
  setUserName() {
    console.log('suggest username button clicked');
    this.view.form.patchValue(  {
      username:
      {
        lastname: 'singlevalue'
      }
    });
  }

To include a template based form control in reactive form group, set ngModelOptions to standalone to true as below. 
      <mat-form-field>
        Template form control test
        <input type="text" matInput [(ngModel)]="myTemplateformControlValue" [ngModelOptions]="{standalone: true}">
      </mat-form-field>
      Output: <span style="color: blue;">{{myTemplateformControlValue}}</span>


The ts file only needs to define a string attribute for it.
myTemplateformControlValuestring;

Additional comment

For using html element validation, there is no need to wrap the input html elements in a form, as long as the element has ngModel attribute defined for it, the angular build-in validation rule can work on the element.

The html and ts code can access the detailed validation error using the local reference variable as shown below

Html file
<input type="text" id="lastname" class="form-control" ngModel name="lastname" required minlength="5" #lre="ngModel">
<span class="help-block" style="color:red" *ngIf="lre.errors && lre.errors.required">lastname is required<br></span>
<span class="help-block" style="color:red" *ngIf="lre.errors && lre.errors.minlength">lastname is min length is 5<br></span>
<button type="button" class="btn btn-primary" (click)="onClick(lre)">submit</button>

TS file
import { Component, OnInit, ViewChild } from '@angular/core';
import { NgForm, NgModel } from '@angular/forms';

export class Cmp2Component {
  // @ViewChild('lre', {static: true})  lastName: NgModel;
  constructor(public activatedRoute: ActivatedRoute) { }

  onClick(e: NgModel) {
    console.log(e);
  }
}

Thursday, October 31, 2019

EventEmitter, Promise, Observable, Subject, BehaviorSubject difference

In Angular project, notification information can be passed from sender's web component to receiver's web component through eventEmitter, Observable and Subject. Depends on the requirement, different type should be selected.

Assuming in sender's web component, when a button is clicked, a new stock price should be updated and received by receiver's web component. The logic of managing the notification message is implemented in a separate service component

1. using EventEmitter

The messaging service should be registered in app.component.ts as a service provider
import { EventEmitter } from '@angular/core';
export class MessagingService {
    stockEventEmitter = new EventEmitter<number>();
}
sender.ts
import { MessagingService } from '../messaging/messaging.service';
export class Cmp1Component implements OnInit {
  stockPrice = 100;
constructor(public activatedRoute: ActivatedRoute, public router: Router, private messaging: MessagingService  ) 
{ }

onUpdateStockPrice(priceChange: number) {
    this.stockPrice = this.stockPrice + priceChange;
    this.messaging.stockEventEmitter.emit(this.stockPrice);
  }
}


Receiver.ts
import { MessagingService } from '../messaging/messaging.service';
export class AppComponent implements OnInit, OnDestroy {
  stockPrice: number;
  constructor(private router: Router,
              public activatedRoute: ActivatedRoute,
              private messaging: MessagingService) {
  }
  ngOnInit() {
    this.messaging.stockEventEmitter.subscribe( price => {
      this.stockPrice = price;
    });
  }
For eventEmitter, the event source is shared by all subscribers, all subscribers are passive listeners, and the event source decides when to send the updated event data to the listeners.
In addition, eventEmitter can only emits the same data type defined in emitter constructor, and does not provide ways to allow sender tells receiver if error happens, or if this messaging operation is ended.  This issue can be solved using Angular Subscribe.
2. Promise

Similar to event, promise pushes data to listener when it is ready, so listener does not need pull the data by itself. However, a promise instance cannot be shared by multiple listeners, each promise object can only server one listener through the registered callback method, it works like a regular asynchronous function call. 
Besides returning the normal successful response, promise can also return error result to receiver.

    const p = new Promise((resolve, reject) => {
      console.log('Promise operation starts');
    
      const r = Math.random();
      if (r > 0.5) {
          console.log('build world successful');
          resolve(r);
      } else {
          console.log('build world failed');
          reject('world is falling');
     }
  } );

 p.then(r => {
        console.log('home build success with ' + r + ' rooms');
 })
 .catch((e) => {
        console.log(e);
 });
The promise constructor method starts when creating the promise object, even if there is no next method registered to get the result. 
3. Observable
Observable is similar to promise, but the observer can get multiple result set from observable. Actually all promise object can be converted to observable. The observable provides next, error and complete method for sender and receiver to handle the success, error and complete status. 
Although multiple observers can subscribe to the same observable instance, each observer will create its own observable instance by calling the obserable costructor, so unlike event emitter, there is not a shared data source to serve multiple subscribers.
Unlike promise, an observable will only start its life cycle when subscriber subscribes to it. At that moment, observable will execute its constructor method to start emitting data. Its life ends when subscriber calls unsubscribe method, or when observable emits error or complete data.
When used as a messaging service, both the observable object for pushing data out, and the subscriber for receiving data need to be exposed to public. It would be better to if a single object is exposed, which can be used by both sending and receiving the sender and receivers to broadcast and receive messages. This can be done by Angular Subject object.
messaging.service.ts
import { EventEmitter } from '@angular/core';
import { Observable, Subscriber } from 'rxjs';
export class MessagingService {
    stockObservable: Observable<number>; // for receiver to subscribe the notification
    stockSubscriber: Subscriber<number>; // for sender to send notification
    constructor() {
        this.stockObservable = new Observable( (subscriber: Subscriber<number>) => {
            this.stockSubscriber = subscriber;
        });
    }
}

sender.ts 
import { MessagingService } from '../messaging/messaging.service';
import { Subscriber } from 'rxjs';
export class Cmp1Component implements OnInit {
  constructor(public activatedRoute: ActivatedRoute, public router: Router, private messaging: MessagingService  ) { }

  onUpdateStockPriceByObservable(priceChange: number) {
    this.stockPrice = this.stockPrice + priceChange;
    this.messaging.stockSubscriber.next(this.stockPrice);
  }
  onErrorStockPriceByObservable() {
    this.messaging.stockSubscriber.error('error happened in stock price update');
  }
  onCompleteStockPriceByObservable() {
    this.messaging.stockSubscriber.complete();
  }
}
receiver.ts
import { intervalSubscription } from 'rxjs';
import { MessagingService } from '../messaging/messaging.service';

export class AppComponent implements OnInit, OnDestroy {
  private stockObservableSub: Subscription;
  constructor(private router: Router,
              public activatedRoute: ActivatedRoute,
              private messaging: MessagingService) {
  }
  ngOnInit() {
    this.stockObservableSub = this.messaging.stockObservable.subscribe( price => {
      this.stockPrice = price;
    }, error => {
      this.stockPrice = -1;
      this.stockPriceError = error;
    }, () => {
      this.stockPrice = -1;
      this.stockPriceError = 'observable completed!';
    }
    );
  }
  ngOnDestroy(): void {
    this.sub.unsubscribe();
    this.eventSub.unsubscribe();
    this.stockObservableSub.unsubscribe();
  }
}

3. Subject
Subject is a special type of observable, and can broadcast multiple data set to multiple subscribers. This is similar to event emitter. 
Subject is both functions to allow multiple subscribers to subscribe to it, and function to emit new data.
One feature missed in regular Subject object is it is not sticky. So after a listener registers a Subject, it will not automatically get the last value sent by the Subject, until the next time when Subject sends new message to listeners. This may not work in all scenarios, for example, as a stock price listener, when a receiver registers to get the price for a stock, it should immediately receive the last price broadcast by sender, without having to wait to get any value until the next stock price update. In this case, BehaviorSubject can be used to receive the initial default value sent by sender.

messging.service.ts
import { EventEmitter } from '@angular/core';
import { Observable, Subscriber, Subject } from 'rxjs';
export class MessagingService {
    stockSubject = new Subject<number>();
}
sender.ts
import { Component, OnInit } from '@angular/core';
import { MessagingService } from '../messaging/messaging.service';
import { Subscriber } from 'rxjs';
export class Cmp1Component implements OnInit {
  constructor(public activatedRoute: ActivatedRoute, public router: Router, private messaging: MessagingService  ) { }
  onUpdateStockPriceBySubject(priceChange: number) {
    this.stockPrice = this.stockPrice + priceChange;
    this.messaging.stockSubject.next(this.stockPrice);
  }
  onErrorStockPriceBySubject() {
    this.messaging.stockSubject.error('error happened in stock price subject');
  }
  onCompleteStockPriceBySubject() {
    this.messaging.stockSubject.complete();
  }
}
receiver.ts
import { Component, ViewEncapsulation, OnInit, OnDestroy } from '@angular/core';
import { interval, Subscription } from 'rxjs';
import { MessagingService } from '../messaging/messaging.service';
export class AppComponent implements OnInit, OnDestroy {
  private stockSubjectSub: Subscription;
  stockPrice: number;
  stockPriceError: string;
  constructor(private router: Router,
    public activatedRoute: ActivatedRoute,
    private messaging: MessagingService) {
  }
  ngOnInit() {
    this.stockSubjectSub = this.messaging.stockSubject.subscribe(price => {
      this.stockPrice = price;
    }, error => {
      this.stockPrice = -1;
      this.stockPriceError = error;
    }, () => {
      this.stockPrice = -1;
      this.stockPriceError = 'subject completed!';
    }
    );
  }
}
4. BehaviorSubject, ReplaySubject
BehaviorSubject is a special Subject, it allows to set an initial value in constructor, so there is always a value to be sent to subscriber when subscribing to a behaviorSubject. If next method is called on subscriber later, then the new value will be read by the observer's next method.
messaging.ts
import { EventEmitter } from '@angular/core';
import { Observable, Subscriber, Subject, BehaviorSubject } from 'rxjs';
export class MessagingService {
    stockBehaviorSubject = new BehaviorSubject<number>(1000);
}

ReplaySubject enables subscriber to specify how many old value, or how long of time should be cached and replayed to the new subscriber.

AsyncSubject is a subject where only the last value of the Observable is sent to its observers, and only when the execution completes.

Tuesday, October 29, 2019

Manage multiple git accounts for github authentication on Windows 10 / Mac

By default, Windows 10 manages git authentication username and password automatically without you to configure the username and password from git configuration. The credential is saved in Windows credential store, and can be accessed from Control Panel->User Account->Manage Your Credentials->Windows Credentials.

As a result, when checking the username and password information from git configuration by running
git config --list
or
git config --global --list
You will not see the git username and password information there.

One problem is, Windows only allows to store a single username and password for your github credential, if you have more than one github accounts, then in order to switch to different git account, you will have to update the username and password from Windows Control panel's Manage your credentials page. (open from: Control Panel -> Credential Manager ->Windows Credentials)

On Mac, the git account information is saved in keychain tool. To switch between different git user account, first open KeyChain tool, In Category section, select all items. Then input "github" in top right search text field, and select the matched item for githbu, and update the user name and password for the record.

Actually, there is simple way to store and use multiple git accounts on a single windows box by following the below steps:
1. run
git config --global credential.github.com.useHttpPath true
from command line
2. open Windows control panel->Credential Manager->Windows Credentials and delete the saved github.com credential if existing.


Note, Github is about to deprecate password authentication, and will replace the password with personal token. If you use gitbut's username/password to log, then you will need to replace the password with personal token in your saved github credential in windows or mac.
To do so, first go to github's "Settings->Developer settings->Personal access tokens" web page to generate a new personal access token, and then copy the generated token, and replace the saved  password with the personal token. The username/personal token can be used for authentication in the same way as username/password. 

Friday, October 18, 2019

Angular css style and view encapsulation

For angular project, the style defined in component's css file is encapsulated for the current component, so the style does not apply to the global scope, or the indirect children components contained within the current component.

For example, appComponent has the below html and css definition

html:
<p>The app component title</p>
<p myattribute>the app component content</p>
<div class="container" style="background-color:yellow;">
  <div class="row">
    <div class="col-sm" >
      <app-cmp1></app-cmp1>
    </div>
    <div class="col-sm">
      <app-cmp2></app-cmp2>
    </div>
  </div>
</div>
css:
p {
    background-color: green;
    font-weight: bold;
}
p[myattribute] {
    background-color: pink;
}
Then when the app is running on browser, the defined css style will automatically be added an attribute selector as 

p[_ngcontent-gio-c0] {
    background-color: green;
    font-weight: bold;
}

p[myattribute][_ngcontent-gio-c0] {
    background-color: pink;
}

where _gncontent_gio-c0 is the random attribute added to the elements defined in appComponent.htm. The runtime element of appComponent looks like as below:
Note every elements defined in appcomponent.html has the new ng attribute of _ngContent-gio-c0, so the defined css style in appcomponent.css can be applied to them.
Similarly, the child element of app-cmp1 element has _ngcontent_gio_c1 defined on it. as a result, any indirect html elements defined in app-cmp1 will not inherit the css style defined in the parent components of appcomponent, as they have a different attribute generated by angular..

Css style files added into compoent's styleURls will always has this ng style attribute selector added for it when inserting the styles into index.html. However, styles files added in component.html will be handled differently depending on whether full url or relative url are used to in style link's href url. If relative url (without http(s) scheme) is used, then the style will have ng attribute selector.

<link rel="stylesheet" href="assets/mystyles.css">

If absolute url (with http(s) scheme) is used, then the style will not have ng generated attribute, so the style will be applied globally, and may affect other elements by accident.
<link rel="stylesheet" href="http://localhost:4200/assets/mystyles.css">
There are two additional ways to add external css style files to angular project:
1. set global css style by adding the css style url in the project's styles.css file, as mentioned in its comment of  "/* You can add global styles to this file, and also import other style files */

2. in the web component's css file, add the external css file with @import statement as shown below:
@import "https://maxcdn.bootstrapcdn.com/bootstrap/4.3.0/css/bootstrap.min.css";

Now the question come, how can we set the style to the html elements of a web component from the holding html page of the web component. For example, how to set style of p element of app-cmp1 from root appComponent.html and its css file. The easy way to do so is applying ::ng-deep to styles. ::ng-deep will remove the ng attribute selector when adding css style at runtime, so it makes the style global available. Note ng-deep is marked as deprecated, although no alternative available for now.
::ng-deep p {
    background-color: pink;
}
Other than ::ng-deep, another option is using component module configuration's encapsulation settings. 
ViewEncapsulation.ShadowDom 
ViewEncapsulation.None
which will allow you to set the global css style from your component's css code. ShodowDom is a better option without the need to generate the random angular attribute id, but it is not supported by all browser, particularly by IE. When using ViewEncapsulation.None, be sure to limit the scope of the css style to be applied, so it will not affect other elements by accident.

One solution of using ViewEncapsulation.None without polluting the angular project's global css style is, using the regular css style for general web component css styles. But creating a separate web component with empty html element, and special css styles that need to be applied globally, so that only a very limited css styles are exposed by this dummy web component.

Note:
1. external css url (from remote cdn) starting with http or https  cannot be directly added into component's ts file's styleUrls list. If external css style should only be applied to a particular web component, then the recommended way is importing the whole npm package (like bootstrap or material design) into the project, and then add the css file from local relative path into the component's style files. For example, the below code in a webcomponent's css file import another css file from a different package (from @ng-select). In this way, when loading the css style file, it will have the angular generated attribute, so those css style will not be applied globally.
@import "~@ng-select/ng-select/themes/default.theme.css";
@media screen and (max-width: 769px) {
    .container-size{
        margin: 1.2em;
    }
}
2. when external css file loaded from web component's html file's as css link reference, the css styles are added into DOM tree without angular random id. The reason of why the style definition can still be applied to web component's html elements is, those styles are applied globally to all elements, no matter the elements have the angular generated attribute or not.

Friday, October 11, 2019

Notes about angular theme style

1. Can default npm bootstrap package work with angular project?
The default npm package published by https://getbootstrap.com/ can be installed by
npm install bootstrap

Or skip the npm installation and directly include the css style and javascript file in the html file as 
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"> 
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script

The default npm package's package.json shows it depends on jquery library. The jQuery depended by  default bootstrap implementation has conflict with angular, as jquery is not compatible with angular project due to the different way to render the DOM element.

So default bootstrap npm package cannot be used by angular project directly. 

If the angular project only needs the bootstrap css style without jQuery dependency, then the angular project can just include the bootstrap in its css style, and the function works as expected. 

But if the angular project depends on bootstrap's javascript dependency, then it will need to use third party library to support bootstrap without jQuery's dependency, such as ngx-bootstrap.

2. What bootstrap components requires javascript library?
Please see https://getbootstrap.com/docs/4.0/getting-started/introduction/ for bootstrap components that requires javascript dependency, they include
  Alerts for dismissing
  Buttons for toggling states and checkbox/radio functionality
  Carousel for all slide behaviors, controls, and indicators
  Collapse for toggling visibility of content
  Dropdowns for displaying and positioning (also requires Popper.js)
  Modals for displaying, positioning, and scroll behavior
  Navbar for extending our Collapse plugin to implement responsive behavior
  Tooltips and popovers for displaying and positioning (also requires Popper.js)
  Scrollspy for scroll behavior and navigation updates

3. what is ng-bootstrap and ngx-bootstrap npm package?
ng-bootstrap and ngx-bootstrap npm package were created to use bootstrap function in angular project without depending on jQuery.
ngx-bootstrap is a new version of ng-bootstrap, so it should be used in the new angular project.
As ngx-bootstrap only replaces default bootstrap package's jquery part with its own javascipt library, so ngx-bootstrap still uses the same css style definition bt default bootstrap library. 

That is why when using ngx-bootstrap package, the CND for the css style file link is same as default bootstrap css CDN link.
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet">
as show in https://valor-software.com/ngx-bootstrap/#/documentation#getting-started 
4. Careful about bootstrop css version
When using bootstrap css style in angular project to render html elements, it is important to match the element style settings with the matched bootstrap versions. As different major version of bootstrap requires different style settings. The angular project will not render properly when using 4.x.x css style with 3.x.x html element settings.


5. Difference between bootstrap and material for angular library
Both bootstrap and material for angular are css styles for html ui component, and both of them can be used for angular project. 
Bootstrap is developed by Twitter, and has a bigger user base. 
Material for angular is developed by angular team and is better integrated with angular project. Bootstrap and Material for angular can be used in the same angular project.

Wednesday, October 2, 2019

Dependency setting in package.json for angular library project and app project

dependencies:
dependencies node defined in package.json will be installed in application's node_modules folder, and used by the library and application project at runtime. There is no difference between library project and application project.

devDependencies:
modules specified in devDependencies is mostly used for compiling and building the library project, so only developers of the app or library need them. For library project, the devDependencies node should only exist in root application's package.json, and should not exist in library project's package.json, so that those information will not be exposed to the library's output package.json, as users of the library do not need to know or care about those modules.

peerDependencies:
peerDependencies node is mostly used by library projects, the packages specified in peerDependencies will not be installed when running "npm package" on the library project, the information specified in peerDependencies node only indicates which version of dependencies packages are required by the library project at runtime, and the host application's package.json must include the related packages with compatible versions, otherwise an error will be reported for missing the required peerDependent packages.

whitelistedNonPeerDependencies:
To avoid developers to add a package in dependencies section by accident, (instead of adding it into peerDependencies section), angular build will fail by default if it finds a such package.
If developers are certain a dependent package should be added into dependencies section instead of peerDependencies section, then developers need to explicitly add the package into ng-package.json's whitelistNonPeerDependencies section to avoid the build failure. Adding a package in whitelistedNonPeerDependencies indicates the developers are certain that a separate copy of the package should be loaded only for the current library.







Tuesday, September 17, 2019

Javascript callback, promise, await and observable

In traditional language, parallel calculation is handled by multithread. Basically, the application creates multiple threads and the operation system is responsible to manage and schedule time slice for each thread to run.

For javascript (and typescript), there is only one thread allow to run in a application, so multiple thread is not an option. Instead, async method is used to support parallel calculation, so that multiple tasks can run at the same time. Callback method, promise, async-await, and observor are some common ways for async method call. A simple way to distinguish sync and async method is for sync method, the next line after calling the sync method will not be called until the actual result is returned, while for async method, the next line will be called immediately no matter how long it will take to actually get the result.

1. callback is simplest way for executing async call, it passes the callback method to handle the result later, so there is no need to block the current call stack.
The drawback is when executing an async method, the onsuccess or onerror callback methods needs to be passed into the async method as parameters. If an async method needs to call another async method, then all the callback methods needs to be chained together, which causes the code not easy to read or maintain.

The below is a sample of using callback for async method to first build world, and then build a home.

 
  buildTheWorld(onsuccess, onerror) {
    // tslint:disable-next-line: only-arrow-functions
    setTimeout( () => {
      const r = Math.random();
      if (r > 0.5){
        console.log('build world successful');
        onsuccess(r);
      } else {
        console.log('build world failed');
        onerror();
      }
    }, 3000);
  }
  buildTheHome(r, onsuccess, onerror){
    // tslint:disable-next-line: only-arrow-functions
    setTimeout( function() {
      const s = Math.random();
      if (s > 0.5) {
        const room = r * 10;
        console.log('build home successful');
        onsuccess(room);
      } else {
        console.log('build home failed');
        onerror();
      }
    }, 3000);
  }
//not easy to read the caller code
 onClickMe() {
    const that = this;
    this.buildTheWorld(
      (r) => {
        that.buildTheHome(r, 
          // tslint:disable-next-line: only-arrow-functions
          (room) => {
            console.log('My new home has ' + room + ' rooms');
          },
          () => {
            console.log('Homeless again');
          }
        );
      },
      () => {
            console.log('No home without a world');
      }
    );
}
2. Promise can be used to simplify the javascript callback syntax, where, caller sets the success or error callback method on the returned promise object.

Theoretically, when implementing an async method, the logic should not need to care about the callback method information, such as how the result will be processed by caller, that information should be managed by caller, and should not pass into the async method. This is how promise handles the javascript async method call.

Basically, the async method will not accept onsuccess and onerror callback, instead, it returns an promise object to caller. Caller can set callback method to handle the promise result using Promise.then method. The creator of the promise calls resolve or reject to send the async result to the caller for consumption. Once the async result is available, the caller's callback method will be called. In this way, the callback method is limited in caller's scope and never need to be passed into async method as parameters. Then method will return immediately, but it will call the actual result handler until after the result is available in future.

Another benefit of using promise is chaining promise result. A promise handle can return a new promise, and so the then or catch method can be chained to sequentially handle the async request and result. Similar to try/catch, when an error or exception happens, all resolve handler will be skipped until it gets the first error/catch handler to handle the error.

The below sample is the function implemented using promise
  promiseTest() {
    this.buildTheWorldPromise()
    .then(result => {
        console.log('world is built');
        return this.buildTheHomePromise(result);
    })
    .then(r => {
        console.log('home build success with ' + r + ' rooms');
    })
    .catch((e) => {
        console.log(e); // get here if failed to build world or build home
    });
  }
  buildTheWorldPromise(): Promise<any> {
    const p = new Promise((resolve, reject) => {
      setTimeout( () => {
        const r = Math.random();
        if (r > 0.5) {
          console.log('build world successful');
          resolve(r);
        } else {
          console.log('build world failed');
          reject('world is falling');
        }
      }, 3000);
    });
    return p;
  }
  buildTheHomePromise(r): Promise<any> {
    const p = new Promise((resolve, reject) => {
      setTimeout( () => {
        const s = Math.random();
        if (s > 0.5) {
          const room = r * 10;
          console.log('build home successful');
          resolve(room);
        } else {
          console.log('build home failed');
          reject('home is falling');
        }
      }, 3000);
    });
    return p;
  }

3. Await can be used to simplify the code and write synchronous method with promise.
Basically, when a function definition includes async keyword, it tells this method will return a promise, instead of data type specified by the method body's return statement. For example, if an async method returns an integer, then the actual return type to the caller is a promise which wraps a integer data. When the actual data (like a string or integer) is resolved by the promise, that is, when the async method returns from the function, the actual return data will be resolved by promise, and then return to the caller in its then method. 
Within an async function, for any method call that returns a promise, or any async method, add await keyword before the call indicates the call in the current method will be blocked and wait until the promise is fulfilled with actual returned value, either resolved or rejected, before the next line of code gets executed to handle the returned data. As a result, the returned value after await is no longer the promise type returned by calling method, instead, await will get the actual data type fulfilled by the promise. This effectively allow developers to write synchronous code when calling asynchronous method. 
The above sample can be simplified as below using await method
  async awaitTest() {
    try {
     // returned r is actual data, not a promise
      const r = await this.buildTheWorldPromise();
      console.log('world is built: ' + r);
      const h = await this.buildTheHomePromise(r);
      console.log('home build success with ' + h + ' rooms');
    } catch (e) {
      console.log(e);
    }
  }
4. Observable
One issue with promise is it can only handle a single result. If an async operation returns multiple result to caller, observable can be used to handle the async result. 
Observable is implemented by RsJx library as a common pattern. 
Similar to promise, the creator of the observable can call observable.next to send success result to caller, or call observable.error to send failed result to caller, in addition, caller can also call observable.complete to tell caller the async operation is finished. 
Unlike promise, the observable creator can call observable.next multiple times to send multiple result to caller to process. Although it can only call observable.error or observable.complete once.