Post

Angular Section 1,2. The Basics

References

  • How an angular project is started

What is Angular

  • Angular is a js framework for (SPA’s) Single page applications

What is a SPA

  • Single page application
  • Single html file is loaded at the start, but as you navigate around the site it is still the same html file, It is only rendering different views on the page with javascript loading it in the background

Why is this good?

  • good for performance
  • the client no longer has to go out and talk to the server with every request like it used to. Instead it only reaches out to the server in the background when it needs some additional info from the server making it very responsive

Angular Versions Explained

  • alt-text
  • started with AngularJS (Angular 1)
    • totally different than what angular is today
    • not future proof because of fundamental structure
    • Called “Angular JS”
  • Angular 2 was a complely re-write
    • released in 2016
    • Called just “Angular”
  • Angular 4
    • Angular 3 was not released for internal things
  • Angular 10, 11, 12, …
    • new major version is released every 6 months
    • small, incremental, backwards-compatiable changes

Angular Pre-requisites & Install

  • Node is required
  • I am using nvm for my node version management
  • nvm use 16.14
  • npm install -g @angular/cli
  • ng version
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
tpool@tpool-thinkpad-l480:~/Playground/Udemy/Angular/Section1/my-first-app$ ng version

     _                      _                 ____ _     ___
    / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
   / △ \ | '_ \ / _` | | | | |/ _` | '__|   | |   | |    | |
  / ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | |
 /_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|
                |___/
    

Angular CLI: 16.2.8
Node: 16.14.1
Package Manager: npm 8.5.0
OS: linux x64

Angular: 16.2.11
... animations, common, compiler, compiler-cli, core, forms
... platform-browser, platform-browser-dynamic, router

Package                         Version
---------------------------------------------------------
@angular-devkit/architect       0.1602.8
@angular-devkit/build-angular   16.2.8
@angular-devkit/core            16.2.8
@angular-devkit/schematics      16.2.8
@angular/cli                    16.2.8
@schematics/angular             16.2.8
rxjs                            7.8.1
typescript                      5.1.6
zone.js                         0.13.3
    
[1]+  Done                    code .

Angular CLI

Create new project

  • ng new <project-name> --no-strict
    • --no-strict
      • Strict mode improves maintainability, helps you catch bugs ahead of time, and turns runtime errors into compile-time errors.
    • common convention to use lowercase letters for the project name
    • then it will ask you the following
      • add angular routing?
      • which stylesheet format you would like to use

You will then see the following of angular bootstrapping your application

  • alt-text

Run your application

  • ng serve
  • it will run on port 4200 by default

You will see this if you navigate to localhost:4200

  • alt-text

Angular project structure

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
your-angular-app/
│
├── e2e/                  # End-to-End test files
│
├── node_modules/          # Node.js modules (third-party packages)
│
├── src/                   # Source code of your Angular app
│   │
│   ├── app/               # Main application code
│   │
│   ├── assets/            # Static assets (images, fonts, etc.)
│   │
│   ├── environments/      # Environment-specific configuration
│   │
│   ├── index.html         # The main HTML file
│   │
│   ├── main.ts            # Entry point for the application
│   │
│   ├── styles.css         # Global CSS styles
│   │
│   └── ...
│
├── .angular.json           # Angular CLI configuration
│
├── package.json            # Project dependencies and scripts
│
├── tsconfig.json           # TypeScript configuration
│
├── tslint.json             # TSLint configuration (if used)
│
└── ...

Course Structure

  • alt-text

Ts-node

  • I am using ts-node for typescript REPL for practice and experimenting
  • just type ts-node in the terminal after installing it via npm and you will get a REPL environment for ts

How angular works

  • The typescript we write gets compiled to javascript so that way when the code is deployed, the client can do all the processing on their side

How the does the index.html file know to load angular

  • The script imports at the end of the html file are what the cli imports automatically. This triggers angular

Where is the main method that gets triggered in angular project

  • src/main.ts
1
2
3
4
5
6
7
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';

// bootstrap the AppModule and start the application
platformBrowserDynamic().bootstrapModule(AppModule)
  .catch(err => console.error(err));

Where is this AppModule that gets bootstrapped and starts the angular app

  • src/app
  • this folder has all the parts for the AppModule where app.module.ts has the outer layer

app.module.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

app.component.ts creates the component

1
2
3
4
5
6
7
8
9
10
11
12
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})


export class AppComponent {
  title = 'my-new-project';
}

And app.component.html contains the html code for the AppComponent

Installling bootstrap css for the project

  • npm install --save bootstrap@3
  • we will be using bootstrap 3 for this course

Now update angular.json to include the bootstrap files

  • you can copy the relative path to the boostrap css file you would like to use and copy to the angular.json file
1
2
3
4
"styles": [
  "src/styles.css",
  "node_modules/bootstrap/dist/css/bootstap.min.css"
],

Angular Components

  • The entire application is built upon Components
  • each component has it’s own html, css, and it’s own business logic
  • Allows you to split up your complex application into re-usable parts
  • Best practice says to place components inside their own folder inside the app directory

Creating our own Component (Manually)

  • we want to create a server component
  • server component code will go in src/app/server

We create our component as follows

1
2
3
4
5
6
7
8
9
import { Component } from "@angular/core";

@Component({
  selector: 'app-server',
  templateUrl: './server.component.html'
})

export class ServerComponent {
}

We have simple html code for our component like this

1
<h2>server component</h2>

We have to tell the main AppModule to load our component

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';

// our new server component
import { ServerComponent } from './server/server.component';

@NgModule({
  declarations: [
    AppComponent,
    ServerComponent // register our server component in the app module
  ],
  imports: [
    BrowserModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Now finally we can render our new component in the app-root

1
2
3
4
5
<h3>I'm in the app component</h3>

<br>

<app-server></app-server>

Creating our own component via (CLI)

  • ng generate component servers or for short ng g c servers
  • This will generate the same code and will even update the app.module.ts to add the component to be used
  • THIS IS AWESOME!!!

Inline template & Css

  • you can have your html templates inline with the typescript code instead of in a separate file
  • you have to use template instead of templateUrl
  • you can also use css in the ts file with styles
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-servers',

  // use a html file
  // templateUrl: './servers.component.html',

  // use html inline
  template: '<app-server></app-server><app-server></app-server>',

  // use a css file
  // styleUrls: ['./servers.component.css']

  // use css inline
  styles: [`
  h3 {
    color: dodgerblue;
  }
  `]
})
export class ServersComponent implements OnInit {

  ngOnInit(): void {
    console.log('')
  }

}

Component Selector

  • we can tell angular to have our component be an html element, an id or an attribute
  • selecting by id won’t work
  • pseudo selectors like :hover will not work
  • typically use for html elements

Below is an example of a html element

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { Component, OnInit } from '@angular/core';

@Component({
  // <app-servers> </app-servers>
  selector: 'app-servers',

  templateUrl: './servers.component.html',

  styleUrls: ['./servers.component.css']
})
export class ServersComponent implements OnInit {

  ngOnInit(): void {
    console.log('')
  }

}
1
<app-servers></app-servers>

If we wanted our component to be an html attribute

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { Component, OnInit } from '@angular/core';

@Component({
  // <div app-servers>
  selector: '[app-servers]',

  templateUrl: './servers.component.html',

  styleUrls: ['./servers.component.css']
})
export class ServersComponent implements OnInit {

  ngOnInit(): void {
    console.log('')
  }

}
1
2
<div app-servers="">
</div>

If we wanted our component to be an class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { Component, OnInit } from '@angular/core';

@Component({
  // <div class="app-servers">
  selector: '[app-servers]',

  templateUrl: './servers.component.html',

  styleUrls: ['./servers.component.css']
})
export class ServersComponent implements OnInit {

  ngOnInit(): void {
    console.log('')
  }

}
1
2
<div class="app-servers">
</div>

Databinding

  • Communication between typescript business logic and html template code
  • alt-text
  • 4 types of Databinding
    • String interpolation
      • ``
      • just display the data
    • Property Binding
      • [property] = "data"
      • have the the property be tied to an element
    • Event Binding
      • (event) = "expression"
      • have an even trigger an expression
    • Two-Way-Binding
      • [(ngModel)] = "data"

String interpolation

  • expression placed between the
  • As long as the expression resolves to a string it will work without issue
  • You also cannot write multi-line expression between the curly braces
1
2
3
4
5
6
7
8
9
10
11
12
import { Component } from "@angular/core";

@Component({
  selector: 'app-server',
  templateUrl: './server.component.html'
})

export class ServerComponent {
  // our two variables
  server_id: number = 1000;
  status: string = 'Down';
}
1
<p>Server with ID:  is  </p>

Property Binding

  • bind a property like disabled for a button to a variable
  • [disabled]="allowNewServer"
  • This will bind the !allowNewServer variable to the disabled property
  • so when the allowNewServer is true, the button will be disabled
  • and when allowNewServer is false, the button will not be disabled
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-servers',
  templateUrl: './servers.component.html',
})
export class ServersComponent {
  allowNewServer:boolean = false;
  
  // after two seconds allowNewServerWillBeSetToTrue
  constructor() {
    setTimeout(() => {
      this.allowNewServer = true;
    }, 2000);
  }

}
1
2
3
4
<button class="btn btn-primary" [disabled]="!allowNewServer" >Add server</button>

<app-server></app-server>
<app-server></app-server>

Event Binding

  • we want a button to trigger a function in our code
  • (click)="onCreateServer()"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-servers',
  templateUrl: './servers.component.html',
})
export class ServersComponent {
  // variables
  allowNewServer:boolean = false;
  serverCreationStatus = "No server was created!"
  
  // after the button is created, it will wait for two seconds then disable it
  constructor() {
    setTimeout(() => {
      this.allowNewServer = true;
    }, 2000);
  }

  onCreateServer():void {
    this.serverCreationStatus = "Server was created!";
  }

}
1
2
3
4
5
6
7
<button class="btn btn-primary" (click)="onCreateServer()" >Add server</button>

<p></p>

<app-server></app-server>
<app-server></app-server>

Passing $event to an Event binding

  • we can pass $event to our event functions to pass the event that has happend during the event binding
  • we can manipulate $event in our ts code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Component({
  //
})
export class ServersComponent {
  // variables
  allowNewServer:boolean = false;
  serverCreationStatus = "No server was created!"
  serverName = '';
  
  onCreateServer():void {
    this.serverCreationStatus = "Server was created!";
  }

  // $event gets passed here
  onUpdateServerName(event: Event) {
    // the stuff in parens are just to make tyepscript happy
    this.serverName = (<HTMLInputElement>event.target).value;
  }

}

{: file=’src/app/server/server.component.ts’}j

1
2
3
4
5
6
7
<input 
  type="text"
  class="form-control"
  (input)="onUpdateServerName($event)" 
>

<p></p>

Two-Way Binding

  • to enable two-way binding you must add the FormsModule to the imports array in the AppModule
  • This is done below
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// ..
import { FormsModule } from '@angular/forms';

@NgModule({
  declarations: [
    // ..
  ],
  imports: [
    BrowserModule,
    FormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Here we are binding to the variable serverName

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!-- Binded to the variable -->
<input 
  type="text"
  class="form-control"
  [(ngModel)]="serverName"
>

<!-- Not binded to the model
  meaning if it were to change somewhere else, the change would not be reflected here
 -->
<input 
  type="text"
  class="form-control"
  (input)="onUpdateServerName($event)"
>

<p></p>

Directives

  • directives are instructions in the DOM
  • They are built-in directives into angular
  • You can also create your own like we have been doing like below
  • example below
  • <p appTurnGreen>Receives a green background!</p>
1
2
3
4
5
6
@Directive({
  selector: '[appTurnGreen]'
})
export class TurnGreenDirective {
  // ...
}

NgIf

  • <p *ngIf="serverCreated">Server was created, server name is </p>
  • the *** at the beginning of *ngIf indicates that this is a **STRUCTURAL DIRECTIVE
    • used to change the structure of the view by manipulating the DOM
  • note that p element will not be there if serverCreated is false
  • if serverCreated is true angular will place the p element on the page

else for NgIf

  • we can add an else condition to an *ngIf by looking at the following example
  • *ngIf="serverCreated; else noServer "
    • noServer is referring to the local reference in the code below
  • <ng-template #noServer>
    • the #noServer specifies a local reference that is referred to in the *ngIf above
1
2
3
4
5
6
7
8
<!-- Server created -->
<p 
  *ngIf="serverCreated; else noServer ">Server was created, server name is </p>

<!-- no server created -->
<ng-template #noServer>
  <p>No server was created!</p>
</ng-template>

ng-template

  • The ng-template directive itself doesn’t produce any visible output in the DOM; instead, it acts as a placeholder for content that can be used in conjunction with other directives to control the rendering of that content.
  • It is often used with other structural directives like *ngIf, *ngFor, and *ngSwitch, allowing you to define template fragments

Local References

  • local references, also known as template reference variables
  • are used to capture references to elements or directives in the template and make them accessible within the component’s TypeScript code.
  • Local references are prefixed with a hash (#) in the template
1
2
3
4
5
<!-- Using a local reference with an input element -->
<input #myInput type="text">

<!-- Using a local reference with an Angular directive (ngIf) -->
<div *ngIf="showElement" #conditionalDiv>This element is conditionally displayed.</div>
  • In the examples above, #myInput and #conditionalDiv are local references to the input element and the ngIf-controlled div element, respectively.
  • You can then access these local references in your component’s TypeScript code by using @ViewChild or @ViewChildren decorators. For example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { Component, ViewChild } from '@angular/core';

@Component({
  selector: 'app-example',
  template: `
    <input #myInput type="text">
    <button (click)="showValue()">Show Input Value</button>
  `,
})
export class ExampleComponent {
  @ViewChild('myInput') myInput: ElementRef;

  showValue() {
    console.log(this.myInput.nativeElement.value);
  }
}

ngStyle

  • an attribute directive
  • dynamically assign a style
  • attribute directives don’t add or remove elements, they only change the elementes they were placed on
1
<p [ngStyle]="{backgroundColor: getColor()}">Server with ID:  is  </p>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@Component({
  // ...
})

export class ServerComponent {
  // our two variables
  server_id: number = 1000;
  status: string = '';

  constructor() {
    this.status = Math.random() > 0.5 ? 'online' : 'offline';
  }

  getServerStatus() {
    return this.status;
  }

  getColor() {
    if (this.status === 'online') {
      return 'green';
    }
    else {
      return 'red';
    }
  }
}

ngClass

  • apply classes to an element dynamically based on a condition
  • [ngClass]="{'online': status === 'online'}"
  • here we are using property binding by surrounding the ngClass directive with []
  • we are saying apply the online class to the p element if status === ‘online’
1
2
3
<p 
  [ngStyle]="{backgroundColor: getColor()}"
  [ngClass]="{'online': status === 'online'}">Server with ID:  is  </p>
1
2
3
4
5
6
7
8
9
10
11
12
@Component({
  // ...
  styles: [`
    .online {
      color: white;
    }
  `]
})

export class ServerComponent {
  // ...
}

*ngFor

  • structure directive
  • adds 0 to many elements based on the loop presented to ngFor <app-server *ngFor="let server of servers"></app-server>
    • this will loop through array of servers and create as many as there is in servers

Getting the index for *ngFor

  • we want to get the index for an element during the loop using ngFor
This post is licensed under CC BY 4.0 by the author.