Learning Angular 17 from official docs and various other sources.
- Envato Tuts+'s Angular tutorial
- Nx, Angular and NestJS
- Secure web app using Angular and AspNetCore server
- MS Identity Samples
- Angular SSR with AspNetCore server
- BFF with .NET and Angular
- GoCloudNative.Bff
Go through the notes here.
Go through the notes here.
Go through the notes here.
Go through the notes here.
Go through the notes here.
Angular in 2 minutes
What is Angular (Great overview!)
Great overview video
Standalone vs NgModule pattern
Standalone components
Angular apps are composed of components. Until now, devs have had to create or update an existing ngmodule in order to use a freshly created component.
Ng modules (feature modules) have been used to specify which components, directives, and pipes are available to use in templates.
@Component({
selector: 'name-card',
template: `
<mat-card *ngIf="name">
<h2>Hello, {{ name | titlecase }}!</h2>
</mat-card>
`
})
export class NameCardComponent {
@Input() name = 'non standalone angular'
}
@NgModule({
declarations: [NameCardComponent],
imports: [CommonModule, MatCardModule],
exports: [NameCardComponent]
})
class NameCardModule {}
The new standalone API makes it possible to write angular components, directives, and pipes without creating an associated ng module. Standalone components are self contained and directly manage their template dependencies.
The focus shifts from ng modules to components.
@Component({
selector: 'name-card',
template: `
<mat-card *ngIf="name">
<h2>Hello, {{ name | titlecase }}!</h2>
</mat-card>
`
imports: [CommonModule, MatCardModule],
standalone: true
})
export class NameCardComponent {
@Input() name = 'standalone angular'
}
-
Create a new GitHub repo (i'm using this current one)
-
Open terminal
-
Run the below command
Ashishs-MacBook-Pro:tour-of-heroes ashishkhanal$ ng new tour-of-heroes --skip-git ? Which stylesheet format would you like to use? CSS ? Do you want to enable Server-Side Rendering (SSR) and Static Site Generation (SSG/Prerendering)? No
ng new
- installs the necessary npm packages and other dependencies that Angular requires.
- creates a new workspace, with a root directory named
tour-of-heroes
. - creates an initial skeleton application project in the
src/app
subdirectory. - creates related configuration files.
Go to the workspace directory and launch the app
cd tour-of-heroes
ng serve --open
The --open
flag opens a browser to http://localhost:4200
.
- Go into
/Users/coolguy/RiderProjects/tour-of-heroes/tour-of-heroes
- Rename the
README.md
generated by angular CLI to be different from whatever is already created by your GitHub repo. For eg: I named itNgCLI-README.md
. - Hit
Command + Shift + .
to view hidden files, copy all files.
- Rename the
- Move all the files you copied from previous step into
/Users/coolguy/RiderProjects/tour-of-heroes
. - Delete
/Users/coolguy/RiderProjects/tour-of-heroes/tour-of-heroes
folder. - Add the files to source control
- Push it to Github with "Commit and Push".
The npm tool window opens when you select a package.json
file in the Project tool window or open it in the editor and select Show npm Scripts from the context menu.
The scripts in your package.json
now shows up in the npm window
Reference: https://angular.io/guide/file-structure
Take a look at this post of mine.
The main.ts
file is the entry point into our app, where we simply bootstrap the Angular application and mount the AppComponent
to the DOM.
The best one is at Typescript's official web site.
tour-of-heroes/tsconfig.spec.json
Lines 2 to 14 in e2baa55
- The
extends
statement means thattsconfig.spec.json
will inherit settings from the basetsconfig.json
file. outDir
tells TS where to emit the compiled JS files. The files in this directory will be used by test runners or development servers to execute your tests."types": ["jasmine"]
instructs the TS compiler to include Jasmine's type definitions in the compilation. They are in "node_modules/@types/jasmine/index.d.ts" file.
This makes the Jasmine's types globally available in your tests files (.spec.ts). It offers advantages like auto-completion, type checking and so on, when you are writing your tests.include
property tells the compiler which files should be included in the compilation."src/**/*.spec.ts"
means include all the.spec.ts
(your test files) in your src folder and its subfolders."src/**/*.d.ts"
does the same for TypeScript declaration files.
The type information from.d.ts
files will be available when writing code in any TypeScript files "included" in your compiler configuration.
tour-of-heroes/tsconfig.app.json
Lines 2 to 14 in e2baa55
-
outDir
tells TS compiler where to output JS files transpiled from your TS source. The primary consumer of the outDir files is the Angular CLI when you run commands likeng build
.It doesn't need to be checked in, so it's in
.gitignore
-
"types": []
is telling TypeScript to include no global type declarations from the "node_modules/@types" directory, which is where third-party library type definitions are typically located. By making this an empty array, it's excluding all global types from "node_modules/@types". -
"include": ["src/**/*.d.ts"]
is specifying that TypeScript should include the type declaration files (.d.ts files) that exist within your src directory. -
"files": [ "src/main.ts" ]
denotes thatmain.ts
is the entry point of your Angular application. TypeScript compiles this file and any files it references directly or indirectly.
Note that it's more common to use "files" for entry points to your application like src/main.ts
and "include" for additional files or glob patterns.
-
This is a configuration file for all angular projects in the workspace. This file is used by the Angular CLI.
For eg: I have 1 project now
-
It includes information about project-wide configuration defaults for Angular build and test tools.
-
Defines how different targets are processed. Targets are predefined tasks like build, test, and lint that are executed by the Angular CLI.
-
Outlines project-specific configurations such as source code locations and file name conventions.
-
Handles the configuration for different environments (dev, prod, etc.).
-
Includes some metadata about the application like name, version, and description at the workspace level and not at the project level (the project level config information would be specified within angular.json).
-
The version field in package.json reflects the version of your entire workspace, which can include multiple projects.
-
It specifies the npm packages being used by the application. There are two types of packages listed: dependencies (necessary for the app to run) and devDependencies (necessary for development).
-
The scripts here can be executed with
npm run <script-name
. For eg:npm run build
. The aforementioned command executesng build
which calls the Angular CLI's build command. The Angular CLI then reads the angular.json file to get build target configuration settings for the project.
They are pretty straightforward.
Make sure you have run this command which hot reloads your changes
ng serve
To create a new component, you can run the generate command by being at the workspace level folder.
To use the above component, put it in app.component.html
like so
<app-heroes></app-heroes>
Now you'll get this error
To fix that, go to app.component.ts
and add this component to the imports array.
imports: [CommonModule, RouterOutlet, HeroesComponent],
Pipe is a function you can use in template expressions to accept an input value and return a transformed value.
For eg: uppercase
It's in /tour-of-heroes/node_modules/@angular/common/index.d.ts
(you don't really have to know this, I just like digging into things)
export declare class UpperCasePipe implements PipeTransform {
/**
* @param value The string to transform to upper case.
*/
transform(value: string): string;
transform(value: null | undefined): null;
transform(value: string | null | undefined): string | null;
static ɵfac: i0.ɵɵFactoryDeclaration<UpperCasePipe, never>;
static ɵpipe: i0.ɵɵPipeDeclaration<UpperCasePipe, "uppercase", true>;
}
Take a look at the static property epipe
that has a type of i0.ɵɵPipeDeclaration<UpperCasePipe, "uppercase", true>
static ɵpipe: i0.ɵɵPipeDeclaration<UpperCasePipe, "uppercase", true>;
i0 just refers to Angular's internal API.
"uppercase"
refers to name of the pipe as a string.
Boolean value of true
denotes whether the pipe is "pure" (doesn't have side effects and won't re-evaluate if the inputs haven't changed).
In your component, import it
import { UpperCasePipe } from "@angular/common";
and add it to imports array
imports: [
UpperCasePipe
],
Now use it in your html inside interpolation binding syntax
<h2>{{ hero.name | uppercase }} Details</h2>
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root',
})
export class HeroService {
constructor() { }
}
A provider ("manufacturer") is something that can create or deliver a service. In this case, it instantiates the HeroService class to provide the service.
The @Injectable
decorator designates this class as a provider that can create a service. So here entire HeroService
class is the "manufacturer".
To make sure that the HeroService
can provide this service, register it with the injector ("delivery service"). The injector is the object that chooses and injects the provider where the application requires it. The injector is a part of Angular's internal system and mechanisms.
Remember it using this analogy:
Annotating a service with @Injectable({ providedIn: 'root' })
is like giving that service to a 'root' delivery man (injector) and saying, "Keep this service in your bag. When a component or another service needs it, provide them with a single instance of it (singleton) from your bag." The 'root' man carries the service throughout your application and shares the same single instance of that service with anyone who asks for it.
Don't follow about the module stuffs there. We do module import stuffs in app.config.ts
in standalone apps.
Read this and add some route definitions in app.routes.ts
export const routes: Routes = [
// This route redirects a URL that fully matches the empty path to the route whose path is '/dashboard'
{ path: '', redirectTo:'/dashboard', pathMatch: 'full' },
{ path: 'dashboard', component: DashboardComponent },
{ path: 'heroes', component: HeroesComponent },
{ path: 'detail/:id', component: HeroDetailComponent }
];
PROPERTIES | DETAILS |
---|---|
path | A string that matches the URL in the browser address bar. |
component | The component that the router should create when navigating to this route. |
After this, just follow along in that tutorial.
When an Observable generates an error, it stops and won't emit further.
Consider this code
tour-of-heroes/src/app/hero.service.ts
Lines 69 to 105 in 81b7f1f
- If an error is encountered during an http call, the method
handleError
is immediately called within thecatchError
operator in the RxJS pipe. - The
catchError
operator intercepts an Observable that fails. It then calls the function it has been provided, which in this case ishandleError
. - Once the
handleError
method is called, it returns another function that accepts the error parameter. At this point, this returned function is not executed yet. - The function returned from
handleError
is then executed by thecatchError
operator, and the caught error is passed to it.
So in summary, handleError
returns a "callback" for catchError
operator that processes the error, and returns a new, non-erroneous "replacement Observable" to prevent the stream from being completely terminated.