Menu Search Sign up

Angular

Project setup

NPM

On Windows: the default location is C:\Users\yourname\AppData\Roaming\npm

All globally installed modules will be under C:\Users\yourname\AppData\Roaming\npm\node_modules

Using Angular CLI to generate an empty project

Reference: https://angular.io/guide/quickstart 

Step 1: Install Angular CLI globally 

To install the Angular CLI globally (accessible by all projects in your host) using npm, open a terminal/console window and enter the following command: 

npm install -g @angular/cli 

Step 2: Create an empty project 

cd C:\your_workspace

ng new icon-nginx-angular 

For the following prompt questions, the answers are given as below:

Would you like to add Angular routing? Yes

Which stylesheet format would you like to use? CSS 

The Angular CLI installs the necessary Angular npm packages and other dependencies. This can take a few minutes. 

It also creates the following workspace and starter project files: 

  • A new workspace, with a root folder named my-app
  • An initial skeleton app project, also called my-app (in the src subfolder)
  • An end-to-end test project (in the e2e subfolder)
  • Related configuration files

The initial app project contains a simple Welcome app, ready to run.

Install & uninstall a node module package you need into your project

cd your_workspace\your_project

npm install ngx-mydatepicker

Where ngx-mydatepicker is the module you want to install

To uninstall: npm uninstall ngx-mydatepicker
 
The install and uninstall will update the package.json file. 
Note: If you got your project source code from somewhere without the node_modules, you can do npm install -E to let npm download all dependencies based on the package.json file

Visual Studio Code

Download, install, and start

https://code.visualstudio.com/download

Download VSCode-win32-x64-1.19.2.zip

Unzip it

Run C:\Users\yourname\Downloads\VSCode-win32-x64-1.19.2\bin\code.cmd to start it

You also need to install tsc (typescript compiler)
npm install -g typescript
tsc -version

And you need to add npm location to your PATH environment variable (On my laptop, it is c:\Users\yourname\AppData\Roaming\npm)

Creating new workspace for an existing Angular project folder

To create a new workspace (for an existing Angular project folder):
File -> Add folder to workspace...
Then:
File -> Save workspace as

Build/debug typescript code step by step

Step 1: Install chrome debugger: simply open the Command Palette (Ctrl+Shift+P) inside VS Code and type "Extensions: Install Extension" command. When the extension list appears, type 'chrome' to filter the list and install the "Debugger for Chrome" extension. The clikc "Reload" to activate

Step 2: Create or updat the file C:\your_workspace\your_project\.vscode\launch.json

{
  // Use IntelliSense to learn about possible attributes.
  // Hover to view descriptions of existing attributes.
  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
  "version": "0.2.0",
  "configurations": [
    {
    "type": "chrome",
    "request": "launch",
    "runtimeArgs": ["--disable-web-security"],
    "name": "Launch Chrome against localhost",
    "url": "http://localhost:4200",
    "webRoot": "${workspaceFolder}"
    }
  ]
}

Step 3 Build the application
Tasks -> Run Tasks -> npm: build
This will run the "ng build"
You will see output of build in the "TERMINAL" window
NOTE: this will delete and recreate the ./dist folder, where you had the compiled code from "ng build"

Step 4 Start a web server to serve the application
Tasks -> Run Tasks -> npm: start
This will run the "ng start", which will build the app again and start a web server to serve the app
You will see output of build in the "TERMINAL"
NOTE: this will delete the ./dist folder, where you had the compiled code from "ng build"

Step 5 Start the debugging
Click the "debug" icon on the left vertical menu bar
Select "Launch Chrome against localhost" and click the ">" play icon. A chrome browser will be launched, and it will go against "http://localhost:4200"

Step 6 Set a breakpoint
Navigate to the line of your source code, Click Debug -> Toggle Breakpoint
You will see a red dot at the break point line

Step 7 Perform user actions
Perform user actions, and you will see it stops at your break point

Step 8 Debug step by step
Now you can debug step by step: click Debug -> Step over, step into, etc.

Step 9 Resume non-debug
Click the ">" play icon to resume non-debugging mode

Step 10 Stop the web server to serve the application
Tasks -> Terminate task -> ecr-emc-manulink_wf (where ecr-emc-manulink_wf is your project name)

Angular Pipes

https://angular.io/guide/pipes

Angular Directives

https://angular.io/guide/attribute-directives

Angular Material 

References 

Getting started
https://material.angular.io/guide/getting-started  

Component Examples
https://material.angular.io/components/divider/examples  

Icons Guide
https://google.github.io/material-design-icons/  

Icon Library
https://material.io/tools/icons/?style=baseline  

Theme Guide
https://material.angular.io/guide/theming  

Color Guide & Tool
https://material.io/tools/color/#!/?view.left=0&view.right=0&primary.color=66BB6A&secondary.color=B9F6CA 
https://material.io/design/color/#color-theme-creation 

Steps 

Step 1: Install Angular Material, Angular CDK and Angular Animations
npm install --save @angular/material@7.2.0 @angular/cdk@7.2.0 @angular/animations@7.2.0 

In above, make sure the version for your Angular material, CDK, and animations are the same as the version of your Angular core package (check your project's package.json file). Otherwise you will see exceptions when running the app. 

Step 2: Install hammerjs for gesture support
npm install --save hammerjs 

Step 3: Install node-sass for theme support
npm install -g node-sass 

Step 4: Install material icon support
npm install material-design-icons (this will install the package under node_modules\material-design-icons)

Step 5: Create your own .scss file

You can put your .scss file under src/assets/css/app_theme.scss
1. Note the difference with example in the documentation:
@import './node_modules/@angular/material/_theming';
2. To know what the colors included in mat-indigo, mat-pink, etc., search in ./node_modules/@angular/material/_theming.scss 

Step 6: Convert your own .scss into .css
node-sass src/assets/css/app_theme.scss src/assets/css/app_theme.css 

Step 7: Reference your theme .css file in your app's src/index.html
<link id="themeAsset" href="assets/app_theme.css" rel="stylesheet"> 

Step 8: Add Material Icons

  1. Copy the folder of "iconfont" from node_modules\material-design-icons to src\assets
  2. In your index.html: <link href="https://assets/iconfont/material-icons.css" rel="stylesheet"> 
  3. In your template html file, do something like this to display the icon: <i class="material-icons md-48">{{item.icon}}</i>

Step 9: Configuring animation vs no-animation in your module
https://material.angular.io/guide/getting-started#step-2-configure-animations 

Step 10: Import the component modules
Import the NgModule for each component you want to use: 

For example, if you want to use MatButton and MatCheckbox: 

import {MatButtonModule, MatCheckboxModule} from '@angular/material'; 

@NgModule({
...
imports: [MatButtonModule, MatCheckboxModule],
...
})
export class PizzaPartyAppModule { } 

How to dynamically swap theme in your Angular code? 

Suppose this is the theme css link in your app's src/index.html:
<link id="themeAsset" rel="stylesheet" href="/path/to/my/theme-name.css"> 

All you have to do is to implement a changeTheme function like below: 

function changeTheme(themeName) {
document.getElementById('themeAsset').href = `/path/to/my/${themeName}.css`;

}  

How to cutomize Angular color themes?

Angular color system supports 12 categories of color that can be applied to components, text, icons, and surfaces. For a detailed discussion and examples of the 12 categories of color, refer to https://material.io/design/material-theming/implementing-your-theme.html#color 

To customize your primary and secondary colors, you can use this link (https://material.io/design/color/the-color-system.html#tools-for-picking-colors) to define your primary and secondary colors, and the page will automatically suggest you the variants of the primary and secondary colors. Then you can just write down the color values, and copy and paste to node_modules\@angular\material\_theming.scss.

Here is an example of customized color that you can define yourself:
$mat-my-green: (
50: #e5f8e8,
100: #c1edc8,
200: #97e2a4,
300: #65d77d,
400: #33cd5f,
500: #00c33e,
600: #00b334,
700: #00a027,
800: #008f19,
900: #006f01,
A100: #c1edc8,
A200: #97e2a4,
A400: #33cd5f,
A700: #00a027,
contrast: (
50: $dark-primary-text,
100: $dark-primary-text,
200: $dark-primary-text,
300: $dark-primary-text,
400: $light-primary-text,
500: $light-primary-text,
600: $light-primary-text,
700: $light-primary-text,
800: $light-primary-text,
900: $light-primary-text,
A100: $dark-primary-text,
A200: $dark-primary-text,
A400: $light-primary-text,
A700: $light-primary-text,
)
);

To customize the background color, modify $mat-light-theme-background (or $mat-dark-theme-background, if you are using dark theme) in node_modules\@angular\material\_theming.scss:

// Background palette for light themes.
$mat-light-theme-background: (
status-bar: map_get($mat-grey, 300),
app-bar: map_get($mat-grey, 100),
background: white,
hover: rgba(black, 0.04), // TODO(kara): check style with Material Design UX
card: white,
dialog: white,
disabled-button: rgba(black, 0.12),
raised-button: white,
focused-button: $dark-focused,
selected-button: map_get($mat-grey, 300),
selected-disabled-button: map_get($mat-grey, 400),
disabled-button-toggle: map_get($mat-grey, 200),
unselected-chip: map_get($mat-grey, 300),
disabled-list-option: map_get($mat-grey, 200),
);

To customize the foreground color, modify $mat-light-theme-foreground (or $mat-dark-theme-foreground, if you are using dark theme) in node_modules\@angular\material\_theming.scss

$mat-light-theme-foreground: (
base: #404040,
divider: $dark-dividers,
dividers: $dark-dividers,
disabled: $dark-disabled-text,
disabled-button: rgba(#404040, 0.26),
disabled-text: $dark-disabled-text,
elevation: #404040,
hint-text: $dark-disabled-text,
secondary-text: $dark-secondary-text,
icon: rgba(#404040, 0.54),
icons: rgba(#404040, 0.54),
text: rgba(#404040, 0.87),
slider-min: rgba(#404040, 0.87),
slider-off: rgba(#404040, 0.26),
slider-off-active: rgba(#404040, 0.38),
);

To apply all your color theme customizations, edit the app_theme.scss file as below:

@import './node_modules/@angular/material/_theming';
// Plus imports for other components in your app.

// Include the common styles for Angular Material. We include this here so that you only
// have to load a single css file for Angular Material in your app.
// **Be sure that you only ever include this mixin once!**
@include mat-core();

// Define the default theme (same as the example above).
$candy-app-primary: mat-palette($mat-my-green);
$candy-app-accent: mat-palette($mat-my-green, A200, A100, A400);
// The warn palette is optional (defaults to red).
$candy-app-warn: mat-palette($mat-red);
$candy-app-theme: mat-light-theme($candy-app-primary, $candy-app-accent, $candy-app-warn);

// Include the default theme styles.
@include angular-material-theme($candy-app-theme);

Then convert your .scss file into .css file:
node-sass src/assets/css/app_theme.scss src/assets/css/app_theme.css 
 
Then include the generated .css file into your index.html file:
<link id="themeAsset" href="assets/css/app_theme.css" rel="stylesheet">

How to customize background color in your Angular app (alternative method)?

First, from the default app_theme.scss as follows:

@import './node_modules/@angular/material/_theming';
@include mat-core();

//to customize background color
$custom-background-color: white;

$candy-app-primary: mat-palette($mat-indigo);
$candy-app-accent: mat-palette($mat-pink, A200, A100, A400);
$candy-app-theme: mat-light-theme($candy-app-primary, $candy-app-accent);

//to customize background color
$background: map-get($candy-app-theme, background);
$background: map_merge($background, (background: $custom-background-color));
$candy-app-theme: map_merge($candy-app-theme, (background: $background));

@include angular-material-theme($candy-app-theme);

$dark-primary: mat-palette($mat-blue-grey);
$dark-accent: mat-palette($mat-amber, A200, A100, A400);
$dark-warn: mat-palette($mat-deep-orange);
$dark-theme: mat-dark-theme($dark-primary, $dark-accent, $dark-warn);

.unicorn-dark-theme {
@include angular-material-theme($dark-theme);
}

Second, convert your .scss file into .css file:
node-sass src/assets/css/app_theme.scss src/assets/css/app_theme.css 

Datetime Picker

https://dalelotts.github.io/angular-bootstrap-datetimepicker/index.html 

In app.component.ts:

export class AppComponent {
  title = 'icon-experiment';
  selectedDate = new Date(2020, 6, 18,8,30,0); //start with a selected date
  onDatetimePickerChange() {
    console.log(this.selectedDate);
  }
}
 
In app.component.html:
 
<dl-date-time-picker
  startView="day"
  maxView="year"
  minView="minute"
  minuteStep="15"
  [(ngModel)]="selectedDate"
  (change)="onDatetimePickerChange()"
>
</dl-date-time-picker>

I18n: ngx-translate

1. put your i18n assets (json format) under src/assets/i18n/en.json (English) or fr.json (French)

2. install the ngx-translate package

npm install @ngx-translate/core --save
npm install @ngx-translate/http-loader --save

3. In <your module>.module.ts:

import {HttpClientModule, HttpClient} from '@angular/common/http';
import {TranslateModule, TranslateLoader} from '@ngx-translate/core';
import {TranslateHttpLoader} from '@ngx-translate/http-loader';

......
export function HttpLoaderFactory(http: HttpClient) {
  return new TranslateHttpLoader(http, "./assets/i18n/", ".json"); //you can change 2nd and 3rd parameters if you put your i18n assets elsewhere

}

......
imports: [
  BrowserModule,
  HttpClientModule,
  TranslateModule.forRoot({
  loader: {
    provide: TranslateLoader,
    useFactory: HttpLoaderFactory,
    deps: [HttpClient]
  }
}),
......

4. Init the TranslateService for your application, in app.component.ts (must be in app.component.ts):

import {TranslateService} from '@ngx-translate/core';
......
  constructor(translate: TranslateService) {
    // this language will be used as a fallback when a translation isn't found in the current language
    translate.setDefaultLang('en');
    // the lang to use, if the lang isn't available, it will use the current loader to get them
    translate.use('fr');
  }

5. use the "translate" pipe in any of your html template files:
<h2>{{'addressContainer.TITLE'|translate}}: ${{total}}</h2>

NOTE:

You can also pass a variable to be translated:

<p style='font-size: 8px;'>{{item.text|translate}}</p>
 
Also, if the text (literal or variable) you pass to be translated is not found in src/assets/i18n/en.json (English) or fr.json (French), the text itself will be displayed.

Parent & Child Component Interaction

Refer to: https://angular.io/guide/component-interaction 

This section tells you, among other things, in your parent component, how to set input parameters for a child component, and how to listen for an event from a child.

How to call a child component's function from its parent component?

https://stackoverflow.com/questions/41965928/angular-2-call-a-function-in-a-child-component-from-its-parent-component 

Techniques of handling user input events and user input values

https://angular.io/guide/user-input 

  • Binding to user input events
  • Get user input from the $event object
  • Restrict type of $event to handle
  • Get user input from a template reference variable
  • Key event filtering (with Angular pseudo-event key.enter)
  • On blur and keyup.enter combined

Techniques of template-driven forms

https://angular.io/guide/forms#the-ngform-directive

https://stackblitz.com/angular/xvlmrmbarrq?file=src%2Fapp%2Fhero-form%2Fhero-form.component.html 

The NgForm directive & 2-way data binding

Angular automatically creates and attaches an NgForm directive to the <form> tag.
The NgForm directive supplements the form element with additional features. It holds the controls you created for the elements with an ngModel directive and name attribute, and monitors their properties, including their validity. It also has its own valid property which is true only if every contained control is valid.

The below example will: display the user's input into {{diagnostic}} as the user enters the input (for diagnostics purpose).

src/app/hero-form/hero-form.component.html (excerpt)

<form #heroForm="ngForm">
......
{{diagnostic}}
<div class="form-group">
  <label for="name">Name</label>
  <input type="text" class="form-control" id="name"
         required
         [(ngModel)]="model.name" name="name">
</div>

<div class="form-group">
  <label for="alterEgo">Alter Ego</label>
  <input type="text"  class="form-control" id="alterEgo"
         [(ngModel)]="model.alterEgo" name="alterEgo">
</div>

<div class="form-group">
  <label for="power">Hero Power</label>
  <select class="form-control"  id="power"
          required
          [(ngModel)]="model.power" name="power">
    <option *ngFor="let pow of powers" [value]="pow">{{pow}}</option>
  </select>
</div>
......

src/app/hero-form/hero-form.component.ts (excerpt)
......
model = new Hero(18, 'Dr IQ', this.powers[0], 'Chuck Overstreet');
// TODO: Remove this when we're done
get diagnostic() { return JSON.stringify(this.model); }
......

src/app/hero.ts
export class Hero {
  constructor(
    public id: number,
    public name: string,
    public power: string,
    public alterEgo?: string
  ) {  }
}

Notice that you also added a name attribute to the <input> tag and set it to "name", which makes sense for the hero's name. Any unique value will do, but using a descriptive name is helpful. Defining a name attribute is a requirement when using [(ngModel)] in combination with a form. The same for the other 2 inputs.

Remember:

  • Each input element has an id property that is used by the label element's for attribute to match the label to its input control.
  • Each input element has a name property that is required by Angular forms to register the control with the form.

Track control state and validity with ngModel

Using ngModel in a form gives you more than just two-way data binding. It also tells you if the user touched the control, if the value changed, or if the value became invalid.

The NgModel directive doesn't just track state; it updates the control with special Angular CSS classes that reflect the state. You can leverage those class names to change the appearance of the control.

StateClass if trueClass if false
The control has been visited.ng-touchedng-untouched
The control's value has changed.ng-dirtyng-pristine
The control's value is valid.ng-validng-invalid

<input type="text" class="form-control" id="name"
  required
  [(ngModel)]="model.name" name="name"
  #spy>
<br>TODO: remove this: {{spy.className}}

Add custom CSS for visual feedback

You achieve this effect by adding these class definitions to a new forms.css file that you add to the project as a sibling to index.html:

src/assets/forms.css
.ng-valid[required], .ng-valid.required  {
  border-left: 5px solid #42A948; /* green */
}

.ng-invalid:not(form)  {
  border-left: 5px solid #a94442; /* red */
}

Update the <head> of index.html to include this style sheet:

src/index.html (styles)
<link rel="stylesheet" href="assets/forms.css">

Show and hide validation error messages

src/app/hero-form/hero-form.component.html (excerpt)
<label for="name">Name</label>
<input type="text" class="form-control" id="name"
       required
       [(ngModel)]="model.name" name="name"
       #name="ngModel">
<div [hidden]="name.valid || name.pristine"
     class="alert alert-danger">
  Name is required
</div>

Reset the form

Note: hereForm is the template variable declared in <form #heroForm="ngForm">
<button type="button" class="btn btn-default" (click)="newHero(); heroForm.reset()">New Hero</button>

Submit the form with ngSubmit

A "form submit" is useless at the moment. To make it useful, bind the form's ngSubmit event property to the hero form component's onSubmit() method:

src/app/hero-form/hero-form.component.html (ngSubmit)
<form (ngSubmit)="onSubmit()" #heroForm="ngForm">

<button type="submit" class="btn btn-success" [disabled]="!heroForm.form.valid">Submit</button> <!--this is the submit button-->
<button type="button" class="btn btn-default" (click)="newHero(); heroForm.reset()">New Hero</button> <!--this is the reset button-->

Bind form's overall validity to the submit button's disabled property

You'll bind the form's overall validity via the heroForm variable to the button's disabled property using an event binding. Here's the code:

src/app/hero-form/hero-form.component.html (submit-button)

<button type="submit" class="btn btn-success" [disabled]="!heroForm.form.valid">Submit</button>

If you run the application now, you find that the button is enabled?although it doesn't do anything useful yet.

Hide the data entry form when data is submitted
 
Wrap the form in a <div> and bind its hidden property to the HeroFormComponent.submitted property.

src/app/hero-form/hero-form.component.html (excerpt)

<div [hidden]="submitted">
  <h1>Hero Form</h1>
  <form (ngSubmit)="onSubmit()" #heroForm="ngForm">

     <!-- ... all of the form ... -->

  </form>
</div>

The main form is visible from the start because the submitted property is false until you submit the form, as this fragment from the HeroFormComponent shows:

src/app/hero-form/hero-form.component.ts (submitted)

submitted = false;

onSubmit() { this.submitted = true; }

When you click the Submit button, the submitted flag becomes true and the form disappears as planned.

Now if you delete the Name, you violate the "required" rule, which is duly noted in the error message. The Submit button is also disabled.

Technique for File Upload (including drag and dop)

https://stackoverflow.com/questions/40214772/file-upload-in-angular 

Angular ngFor & ngIf examples

<li *ngFor="let item of items; index as i; even as isEven; odd as isOdd; first as isFirst; last as isLast; trackBy: trackByFn"> ------ </li>