My Web Dev. Learning Doc.

Reach me at: GitHub, Personal Website, LinkedIn

Angular CLI Commands

Beginning
  • ng new project-name - Create a new project.
  • ng serve --open - Start the live-reloading docs server and open in a browser.
  • ng update - Updates your application and its dependencies.
  • ng add @angular/material - Install angular material
Coding
  • ng generate --help - Showing the list that can be generated.
  • ng add --help - Showing the list that can be added.
Deployment
  • ng build - Build the documentation site.
  • npm install -g now - Install now.sh
  • now login - For first time user to use now.sh.
  • now - Deploy your project.

Angular

How to transfer data from one main component to a modal component

Main Component

const modal = this.modalService.open(DeleteBranchComponent, options);
modal.componentInstance.id = id;

Modal Component

@Input() public id: string;

Reference

Observable

getBranchDetail(id: string): Observable<Branch>{

    return this.http.get<{result: BranchModel}>(this.branchRoute + id).pipe(map(model => model.result))
}
  • <Branch> - the one beside function is what you would return to your caller
  • <{result: BranchModel}> - the one in the get is what you expect from the server

so you receive one thing, and you return other thing, then some transformation must be happening in the middle

How to reload when closing modal

window.location.reload();

or

modal.result.then(() => {
    // this part will run with params where you pass in with this.modalInstance.close()
}, () => {
    // this part will run with params where you pass in with this.modalInstance.dismiss(), can leave blank if no action needed
})

Get params from URL

this.route.snapshot.paramMap.get('id');

or

this.route.params.subscribe(params => {
    this.id =+ params['id'];        
});

Deployment using Visual Studio Code to Microsoft Azure

  • At node.js terminal

    • Move to the directory of the root of the files. Run command dotnet build. After that, run the command dotnet publish -c Release -o ./publish. (Make sure your code able to run through ng build --prod before step 2a.)
    • Find the publish folder and right click on deploy to web app.
    • Open the staging website to check the version of the website.
  • References

API (Bad vs Good Example)

Bad Example

service.ts
updateCardNumber(cardNumber: any): Observable<any> {

    return this.http.put(this.route + "UpdateCardNumber", cardNumber).map( data => return data );
}
component.ts
this.service.updateCardNumber({ CardNumber : this.cardNumber });

Good Example

service.ts
updateCardNumber(cardNumber: number): Observable<any> {  // typed input, observable can be any if we don't care about the response

    const body = { CardNumber : cardNumber } // this depends on server api expected body

    return this.http.put(this.route + "UpdateCardNumber", body) // .map is for transforming one result to another, no point to write if no transformation is needed

}
component.ts
this.service.updateCardNumber(this.cardNumber);

Submit Logic

Case One
submit() {
    line a
    line b 
    line c
}
Case Two
submit () {

    if (x) {
        doSomething.then(() => {
            line a
            line b 
            line c
        })
    }
    else {
        line a
        line b
        line c
    }
}
Case Three
submit () {

    if (x) {            
        doSomething.then(() => {
            _submit();
        })
    }
    else {
        _submit();
    }
}

_submit() {
    line a
    line b
    line c
}

Communicate from parent to child component...

Parent component template
<app-home [title]=" 'Peace' "></app-home>
Child component class
import { Input } from 'angular';

class ChildComponent {
    @Input() title: string;
}

Attribute Directive: NgClass Directive

ngClass Directive: The ngClass directive is used to add or remove CSS classes to an HTML element.

login.component.html
<form class="loginForm"
          [formGroup]="form"
          (ngSubmit)="submit()"
          [ngClass]="{'showFormError': showFormError}">

          # [ngClass]="{property: boolean}"
</form>
login.component.ts
submit(): void {
if (!this.form.valid) {
    this.showFormError = true;
    return;
}
login.component.scss
.showFormError {
    input.ng-invalid {
        border-color: red !important;
    }
}

Attribute Directive: NgSwitch Directive

<div [ngSwitch]="currentPage">
    <div *ngSwitchCase="0"> Current Page is zero </div>
    <div *ngSwitchCase="1"> Current Page is one </div>
    <div *ngSwitchCase="2"> Current Page is two </div>
    <div *ngSwitchDefault> Default Page </div>
</div>

Custom Attribute Directive

ng new generate directive class - Create a new directive.

class.directive.ts
import { Directive, ElementRef, Input } from '@angular/core';

@Directive({
    selector: '[appClass]'
})

export class ClassDirective {

    constructor(private element: ElementRef) {}

    @Input('appClass') set backgroundColor(color: string) {
        this.element.nativeElement.style.backgroundColor = color;
    }
}
component.html
<h1 [appClass]=" 'red' "></h1>

Custom Structural Directives

ng generate directive times

times.directive.ts
import { Directive, TemplateRef, ViewContainerRef, Input } from '@angular/core';

@Directive({
    selector: '[appTimes]'
})

export class TimesDirective {

    constructor(
        private viewContainer: ViewContainerRef,
        private templateRef: TemplateRef<any>
    ) { }

    @Input('appTimes') set render(times: number) {
        this.viewContainer.clear();

        for (let i=0; i<times; i++) {
            this.viewContainer.createEmbeddedView(this.templateRef, {});
        }
    }
}
component.html
<ul *appTimes="5">
    <li>Hi there!</li>
</ul>

Custom *ngFor

ng generate directive times

times.directive.ts
import { Directive, TemplateRef, ViewContainerRef, Input } from '@angular/core';

@Directive({
    selector: '[appTimes]'
})

export class TimesDirective {

    constructor(
        private viewContainer: ViewContainerRef,
        private templateRef: TemplateRef<any>
    ) { }

    @Input('appTimes') set render(times: number) {
        this.viewContainer.clear();

        for (let i=0; i<times; i++) {
            this.viewContainer.createEmbeddedView(this.templateRef, {
                index: i
            });
        }
    }
}
component.html
<ng-container *appTimes="images.length; let i = index">
    <li
        class="page-item"
        [ngClass]="{ active: i === currentPage }"
        *ngIf="checkWindowIndex(i)"
    >

Debug in TypeScript/JavaScript

debugger 
console.log()

Calling API without Observable #1 (Post, Put)

updateProfilePhoto(file: any) {
    const formsData = new FormData(); # FormData() is a built in function. 
    formData.append("file", file);

    return this.http.post(this.route + "ProfilePhoto", formData) # In Postman, the body column need a file
}

updateProfile(body: any, file:any) {

    return this.http.put(this.route + "Profile", body).pipe(mergeMap(result => {
        let observables: Observable<any>[] = [of({})];

        if (file) {
            observables = observables.concat(this.updateProfiile(file.file));
        }

        return forkJoin(...observables);
    }));
}

Calling API with Observable #1 (Get)

service.ts
getData(id: number, skip: number, take: number): Observable<Data[]>{
    const params: any = {
        first-param: userId,
        second-param: skip.toString(),  # What is toString()?
        third-param: take.toString(),
    }

    return this.http.get<DataModel[]>(this.route + 'MiddlePartOfURL', { params: params })
        .pipe(map(models => {
            return models.map(model => new Data(model));   
    }))
}
data-model.ts
export class DataModel {
    PointId: number;
    CreateDate: string;
    Point: number;
    Remark: string;
    Title: string;
}
data.ts
import { DataModel } from "./data-model";
import { Moment } from "moment";
import { BaseClass } from "../base-class";

export class Data extends BaseClass {
    id: number;
    createDate: Moment;
    point: number;
    remark: string;
    title: string;

    constructor(
        model: DataModel
    ) {
        super();
        this.id = model.PointId;
        this.createDate = this.toMoment(model.CreateDate);
        this.point = model.Point;
        this.remark = model.Remark;
        this.title = model.Title;
    }
}
data.component.ts
this.loading = true;

getData(): void {

    const skip = this.array.length;
    const take = 10;

    this.userService.getData(this.userId, skip, take).subscribe(
        (data: Data[]) => {
            this.array = this.array.concat(data);

            if (data.length < take) {
                this.endOfList = true;
            }
        },
        () => {
            this.endOfList = true;
        }
    )
        .add(() => { this.loading = false });
}

Calling API with Observable #2 (Get)

import { of } from 'rxjs';

getUser(reload = false): Observable <User> {
    if (!reload && this.currentUser)
        return of(this.currentUser);

    return this.http.get<UserModel>(this.route + "Profile")
        .pipe(map(model => {
            this.currentUser = new User(model);
            return this.currentUser;
        }));
}

Model Mapping - Translation Layer

To provide a translation layer between server model and data model

service.ts
getData(): Observable<Example[]> {

    return this.http.get<ExampleModel[]>(this.route + "GetData")
        .pipe(map(model => model.map(m => new Example(m))));  # the translation layer 
}
example.ts
import { ExampleModel } from "./example-model";

export class Example {
    id: number;
    title: string;
    selectionTitle: string;
    description: string;

    constructor(model: ExampleModel) { 
        this.id = model.Id;
        this.title = model.Title;
        this.selectionTitle = model.SelectionTitle;
        this.description = model.Description;
    }
}
example-model.ts
export class ExampleModel {
    Id: number;
    Title: string;
    SelectionTitle: string;
    Description: string;
}

Routing

app-routing.module.ts
{ path: 'profile/web-dev', component: WebDevComponent , data: { title: 'Web Development'} },
profile.component.ts
constructor(
    private router: Router,
) {}

this.router.navigate(['wed-dev']);
profile.component.html
[routerLink]="['./web-dev']"

Call nested object from API

<div *ngFor='let item of items'>
    {{ item.something }}
</div>

Perform event click in typescript

click it will direct to this.getAccessment.

click.this.getAccessment

NgbModal

addPopupCard() {

    const option = {
        size: 'lg',
        centered: true
    } as NgbModalOptions;

    this.modalService.open(any-component, option);
}

JavaScript Built In Functions

map

const array1 = [1, 4, 9, 16];

# pass a function to map
const map1 = array1.map(x => x * 3);

console.log(map1);
# expected output: Array [3, 12, 27, 48]

Immediately Invoke Function Expression (IIFEs)

Part 1
(function(name) {

    var greeting = 'Hello';
    console.log(greeting + ' ' + name);

}('John'));
Part 2
function buildFunctions2() {

    var arr = [];

    for (var i = 0; i<3; i++) {
        arr.push(
            (function(j)
                return function() {
                    console.log(j);
                }(i))
        )
    }
}

var fs2 = buildFunctions2();

fs2[0]();
fs2[1]();
fs2[2]();

Closures

function greet(whattosay) {

    return function(name) {
        console.log(whattosay + ' ' + name);
    }
}

greet('Hi')('Tony');

var sayHi = greet('Hi');
sayHi('Tony');

Rxjs

function/of


Git

How to delete git branch in VS code

  • git branch -d <branch-name> or git branch -D <branch-name>
  • git fetch --prune - to remove all remote branches that have been deleted.

How to solve conflict

1. Switch to target branch, then pull the latest.
2. Switch back to the pull request branch.
3. Merge from the target branch.
4. Resolve conflict.
5. Commit and push.

How to write a commit message

Cited from Writing Better Commit Messages.

type(scope): subject 

<body>
<footer>
1. Type of commit
feat:     The new feature being added to a particular application
fix:      A bug fix
style:    Feature and updates related to styling
refactor: Refactoring a specific section of the codebase
test:     Everything related to testing
docs:     Everything related to documentation
chore:    Regular code maintenance
2. Scope (optional)

Provided in parentheses after the type of commit, describing parts of the code affected by the changes or simply the epic name.

feat(claims)
fix(orders)
3. Subject

Short description of the applied changes. - Limit the subject line to 50 characters - Your commit message should not contain any whitespace errors or punctuation marks - Do not end the subject line with a period - Use the present tense or imperative mood in the subject line

feat(claims): add claims detail page
fix(orders): validation of custom specification
4. Body (Optional)

Use the body to explain what changes you have made and why you made them. - Separate the subject from the body with a blank line - Limit each line to 72 characters - Do not assume the reviewer understands what the original problem was, ensure you add it - Do not think your code is self-explanatory

refactor!: drop support for Node 6
BREAKING CHANGE: refactor to use JavaScript features not available in Node 6.

Use this section to reference issues affected by the code changes or comment to another developers or testers.

fix(orders): correct minor typos in code
See the issue for details
on typos fixed.
Reviewed-by: @John Doe
Refs #133

Some Useful References

  1. What Makes a Good Pull Request, Anyway? by Jose Granja.
  2. Writing Better Commit Messages by Apurva Jain.
  3. Git Commit Emoji