Fullstack Angular 14: Architecture & project’s design

Fullstack Angular 14: Architecture & project’s design

In this tutorial with the latest Angular 14 version, we'll learn about the project's design and architecture.

We’ll build a CRM application with an Angular 14 frontend and Node.js backend. Additionally, we’ll use GraphQL with Apollo to build and consume the API and we’ll use a PostgreSQL database with TypeORM to store and access data.

Angular 14 is a TypeScript-based framework created by Google for developing client-side web applications for mobile and desktop. It will be used to consume the server's GraphQL API and to create the application's user interface. In addition, we'll style the UI using Angular Material.

Angular 14 is an entire platform that allows developers to make single-page client apps in HTML, CSS and TypeScript. It provides essential and optional functionality as a group of libraries that you can integrate into your apps.

Angular 14 architecture

An Angular 14 application's architecture is based on a few key ideas. The Angular framework's fundamental building pieces are Angular components arranged into modules which group together similar code to form functional sets.

Note: With the latest version, you can architecture your application as a set of standalone components without modules. Standalone components (and also directives) are in preview mode which means they are not stable yet but they are the future of Angular since they streamline the authoring of components. You can read more about Angular 14 features

TypeScript is a superset of JavaScript developed by Microsoft that brings static typing, enhanced error checking, type safety, and object-oriented programming paradigms to the language before it is converted to JavaScript and processed in web browsers. Furthermore, it works more tightly with code editors and integrated development environments (IDEs), improving the developer experience, especially when implementing large JavaScript applications that should scale.

You may see an Angular 14 application as a group of modules. An application always contains at least one root module that facilitates initialization, and one or more feature modules.

In contrast to other popular JavaScript libraries, such as React, Angular is a platform with built-in libraries for solving common development problems, such as the ones listed below:

  • Angular HttpClient to send HTTP requests and process response
  • Angular Universal to implement server-rendered apps with Angular
  • Angular Material to build UIs with material design components
  • Angular template-based forms to work with forms using directives and HTML
  • Angular reactive forms to create reactive forms making use of RxJS

Angular enables building frontends with both modular and component-based designs, which helps developers develop application using modules and/or components.

When designing an Angular 14 application, you may arrange it into modules and/or components that can be utilized across the application and, with caution, across several apps.

While the Angular functionalities are confined inside built-in modules, new modules may be created to design and arrange your application. Components, services, and any other Angular artifacts may be included in a module. Let's look at modules and components in more detail.

Angular modules

You can think of a module as simply a shell for Angular code that grouped together provides a specific domain functionality. They enable you to separate your application into smaller, more achievable chunks.

Rather than rewriting all of the code from beginning for each new project, you can further group your modules into libraries that other developers or you can re-use.

An Angular module may include services, components, directives, and pipes, and it can be lazy-loaded by the router to optimize the performance of applications.

You may create your own custom modules to implement a requirement or feature in your app, or you can also use the built-in modules that expose the Angular core functionalities, such as forms module which is used to create and validate forms, http client module which is used to make HTTP requests and router module that provides a router as well as a number of useful APIs and components to your Angular application.

One built-in module that you may often see it included in other modules is the common module which provides all of the fundamental angular directives and pipelines, such as NgIf and NgFor.

You can create angular 14 modules by simply using NgModules. NgModule is a TypeScript class that is decorated with the @NgModule decorator.

An Angular 14 application must have at minimum one module, which is called the root module. This is the module that would be used to start the application.

We already have two modules in our Angular CLI-generated project: src/app/app.module.ts and src/app/app-routing.module.ts, which export the classes needed to create the main application module and the routing module.

One of the most important building blocks of a module are components but what is a component?

Angular components

An Angular component is responsible for presenting a section of the application's user interface. A component, for instance, might be used to create your application's home screen, and if you want to achieve far more code reusability, you could then split the home screen into individual components, such as the toolbar, header, and bottom regions.

This enables you to include the navigational and footer components on other webpages of your application avoiding repeating the same code for aspects common by all, or just some, areas of your application.

A component is simply a TypeScript class that has been annotated with the @Component decorator supplied from the Angular core module in terms of code. It also supports an HTML template that can be used inline or written as a standalone HTML file to display content and associate properties and events from the component's class.

Furthermore, a component may be linked with one or more style sheet files that offer styles for the view in the format you've chosen for your project, such as CSS, SCSS, or Sass.

Angular 9+ includes a new renderer engine codenamed Ivy, which is a next-generation compiler and renderer system comprised of a compiler and a suite of runtime instructions.

Ivy leads to lighter production packages, better build times and runtime performance, and simplified debugging. It employs incremental DOM, which involves compiling Angular components and templates into a set of JavaScript instructions that are used to build and modify the Document Object Model (DOM).

Let's return to our application for a second. There are many files in the src/app folder that include the TypeScript logic, HTML template, and CSS style sheet for the app component. The CSS styling for the component are provided via the app.component.css file whereas the file app.component.html contains the HTML code for rendering the component and the app.component.ts file contains TypeScript code that defines the component data and functionality.

The root component gets loaded when the app is started by including the component in the bootstrap array of the application module. To view this, open the src/app/app.module.ts file containing the application module:

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

@NgModule({
 // [...]
 bootstrap: [AppComponent]
})
export class AppModule { }

The root component is also added in the src/index.html file, which is fetched when visitors request your Angular 14 website through a web browser:

<!doctype html>
<html lang="en">
<head>
  <!-- [...] -->
</head>
<body>
  <app-root></app-root>
</body>
</html>

The root component is used just like a regular HTML element, by its selector as shown above. This tells Angular 14 to inject the component and all of its descendants into the DOM.

Navigate to the src/app directory and open the app.component.ts file. The following code should be used to define the root component’s class:

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'client';
}

This is simply a regular TypeScript class with the @Component decorator added to it from the core module. The decorator holds component metadata, such as the following:

  • selector: This is used to access the component from an HTML page in the same way that traditional HTML tags are. Angular may be used to create custom HTML tags that are exclusively available inside your application.
  • templateUrl: This specifies where Angular should search for the HTML template containing the display. markup.
  • styleUrls: This specifies where to obtain component-specific styles that define the component's feel and look.

The life cycle of a component starts when Angular 14 creates an instance of the component's class and ends when the component is destroyed and removed from the DOM.

Angular provides lifecycle hook methods via a bunch of interfaces, each of which offers a mechanism for hooking into significant events in a component's lifecycle.

The ngOnInit function, for example, is provided by the OnInit interface and is executed when the component is initialized. For more information on lifecycle hooks, see https://angular.io/guide/glossary#lifecycle-hook.

Services and dependency injection

Let's look at services and dependency injection now that we've defined modules and components.

In Angular, a service is a singleton that may be supplied to other components or services using dependency injection, which is a mechanism of supplying dependencies to an object.

Don't be confused by this jargon! This basically implies that an Angular component known as the injector is in responsible of constructing a service instance and providing it to the components that require it.

Dependency injection is closely connected to the Angular 14 framework and is used to inject services and other objects into components, giving access to service features without the need to manually make an instance.

Angular services allow you to build applications that meet the following instructions:

In components, you may separate your application's business logic from its presentation logic. Data exchange between components in your application Code reusability implies that you should utilize services to structure and reuse code inside your application to avoid redundancy and starting from scratch.

In general, you should use components to develop the user interface of your application by passing properties and methods to the HTML template (which is in charge of making the view) through data binding and events. More information regarding Angular binding syntax can be found at https://angular.io/guide/binding-syntax.

Services, on the other hand, are required for common things that multiple components need in order to work, such as data fetching from the server.

You may create a service in Angular 14 by using the @Injectable decorator, which lets you to specify the metadata that the framework need to introduce the service as a dependency into another component or service.

So, how do we tell Angular 14 to inject a service?

By simply supplying the dependency as an argument to the requesting component's constructor. That's enough for Angular 14 to deliver a service instance to the component. However, before Angular can do so, we must first provide the service in one of the following ways:

  • By adding the service to the providers array of a component, it becomes unique to that component.
  • By adding the service in the providers array of a module, it becomes accessible just inside the module.
  • By combining the providedIn property with the @Injectable decorator. For more information, see https://next.angular.io/api/core/Injectable.

Adding modules, services and components

We'll look at how to generate modules, components, and services using the Angular 14 CLI.

In Angular, you may create components, services, and modules by using the appropriate Angular 14 CLI command, which creates the absolute minimum code necessary for a basic component, service, or module to work.

Note: With the latest Angular CLI v14, the CLI provides auto-completion for commands which makes it easy for developers and especially beginners to become more productive with the CLI.

Decorators are used by classes such as modules, components, and services. These decorators indicate the artifact category and include information that instructs Angular on how to utilize it.

A component class's metadata ties it with a template that describes its view. A template is a combination of standard HTML plus Angular directives and binding syntax that enable Angular 14 to process the HTML before compiling it for display.

The metadata for a service class contains the information required by Angular 14 to make it accessible to components through dependency injection (DI)

The components of an application often describe a large number of views that are organized hierarchically. Angular offers the Router service to assist developers with defining navigation.

Note: The latest Angular 14, brings more enhanced features to the router, for example, you can set the title of the application from the route configuration.

Let's create our modules, services, and components using the Angular 14 CLI.

Make a module for each functionality of your project. This is a fundamental guideline to adopt. The home feed, for example, may be housed inside a different module. Splitting your system into modules allows you to load components more quickly and manage it more effectively.

The modules

The following modules will be used in our application:

  • A users module that includes login, registration, and profile components.
  • A feed module that contains the component(s) required to display the posts obtained through GraphQL.
  • A shared module may include components shared by other modules in your application.
  • A root module that contains our application's global services as well as common layout components like the authentication service and header and footer components.
  • Shared modules save you time by eliminating the need to import common modules, components, and other artifacts required by multiple modules in your application.

For example, by just importing and exporting ReactiveFormsModule from our shared module, we can skip importing it in both the users and feed modules.

In addition, we'll import and re-export Angular Material component modules into the shared module to make them accessible to the rest of our project's modules.