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.shnow 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;
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 commanddotnet publish -c Release -o ./publish
. (Make sure your code able to run throughng 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.
- Move to the directory of the root of the files. Run command
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
Git
How to delete git branch in VS code
git branch -d <branch-name>
orgit 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.
5. Footer (optional)
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