Angular Best Practices Guide
Angular Best Practices Guide
TABLE OF CONTENTS
Introduction ...................................................................................... 3
1
Angular Development Best Practices
Services .......................................................................................... 16
HTTP .............................................................................................. 19
Conclusion ...................................................................................... 21
2
Angular Development Best Practices
INTRODUCTION
In this guide, we are going to show what we consider to be the best
practices in Angular while developing the client side project in this
framework. During the development process it’s really easy to forget about
some rules and recommendations in Angular, so having the reference to look
at from time to time helps to refresh memory.
ANGULAR CLI
We recommend using the Angular CLI tool while working with the Angular
project.
Why is that?
Well, it will increase your productivity for sure. Angular CLI has its own set
of commands for creating the Angular project, creating components,
modules, services etc…
Not only that we are creating our components faster with Angular CLI, but it
will reference those components into their own modules and will comply with
the naming convention, so we don’t have to worry about it.
We can use a basic set of commands to generate our components but every
command has its own options. For example, if we want to generate
component we would type:
ng g component example_component
3
Angular Development Best Practices
It is going to generate 4 files for us. A component file, an html file, a css file
and a spec file. The last one is for testing purposes. If we don’t wish to have
that last one created we can just add the flag: --spec false. By doing this
Angular CLI will not generate the spec file at all. This is just one of the
options.
File Naming
While creating our files, we should pay attention to the file names. Names
should be consistent with the same pattern in which we mention the file’s
feature first and then the type, dot separated.
4
Angular Development Best Practices
Class Names
When we add names to our classes, we should use upper camel case style
with the added suffix that represents the type of our file:
Folder Structure
Our files should reside in folders named by the feature they represent. This
is important because we can easily identify which business logic we have
implemented in those files inside our descriptive folders:
5
Angular Development Best Practices
Using Interfaces
If we want to create a contract for our class we should always use
interfaces. By using interfaces we can force a class to implement functions
and properties declared inside an interface. Let’s take for example OnInit
interface and its implementation:
constructor() { }
ngOnInit() {
6
Angular Development Best Practices
The TypeScript will display an error if an object doesn’t contain all of the
interface’s properties, and light up intellisense for us while populating that
object:
public user: User;
We can specify optional properties, by using the question mark (?) inside an
interface as well. We don’t need to populate those properties inside an
object:
additionalData?: string;
Using Immutability
Objects and arrays are the reference types in JavaScript. If we want to copy
them into another object or an array and modify them, we should do that in
an immutable way.
7
Angular Development Best Practices
The easiest way to modify objects and arrays immutably is by using the es6
spread operator (…):
this.user = {
name: 'Dzon',
age: 25,
address: 'Sunny street 34'
}
let updatedUser = {
...this.user,
name: 'Peter'
}
We are deep-copying the user object and then just overriding the name
property.
Let’s take a look at how to use the spread operator with arrays:
8
Angular Development Best Practices
from our template file. Properties and functions, which we are going to
reference from the template should always have the public access modifier.
The private ones will be visible to the HTML template as well, but it is not a
good practice due to AoT compilation failure.
Constructor Usage
We should use the constructor to setup Dependency Injection for our
services and that is pretty much it. We shouldn't be doing any work inside it,
especially fetching the data from the server. For any kind of business logic,
we should use the lifecycle hooks in Angular instead.
Even though we can use the service injection inside the constructor:
private router: Router;
constructor(routerParam: Router) {
this.router = routerParam;
}
9
Angular Development Best Practices
Routing Module
The best practice for Angular application is to use a separate routing module
for the router:
const appRoutes: Route[] = [
{ path: 'home', component: HomeComponent },
{ path: '404', component: NotFoundComponent }
]
@NgModule({
imports: [
CommonModule,
RouterModule.forRoot(appRoutes)
],
exports: [RouterModule]
})
export class AppRoutingModule { }
And then to register this new routing module in our app module:
imports: [
AppRoutingModule
]
10
Angular Development Best Practices
Lazy Loading
If we have a multi-modular application, implementing lazy loading is
recommended. The great advantage of the lazy loading approach is that we
can load our resources on demand and not all at once. This helps us in
decreasing the startup time. Modules that we are loading in the lazy-load
manner will be loaded as soon as a user navigates to their routes.
If you want to learn more about the lazy loading feature you may read our
blog post about lazy loading.
Shared module
If we have components, directives or pipes in our project which we want to
share through the entire project, the best way to do that is to register them
inside the shared module file. Then, we need to register the shared module
inside the app module. It is important not to register services in a shared
module. We should register them inside its own feature module or in app
module.
11
Angular Development Best Practices
12
Angular Development Best Practices
Instead, we should separate styles and HTML in their own files and import
them:
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
13
Angular Development Best Practices
constructor() { }
ngOnInit() {
}
public emmitEvent(){
this.redirectOnOK.emit();
}
}
To learn more about decorators and how to use them to create reusable
components, you can read Child components, @Input, @Output Decorators.
14
Angular Development Best Practices
Using Directives
Whenever we have a situation where multiple HTML elements behave
exactly the same (for example: when we hover over the element it receives
the blue color), we should consider using attribute directives. We shouldn't
repeat the hover logic every time we need it on some HTML element. A
much better way would be to create directive and then just reuse it on the
particular element.
@Directive({
selector: '[appHover]'
})
export class HoverDirective {
@HostListener('mouseenter') onMouseEnter(){
this.highlightElement(this.hoverColor);
}
@HostListener('mouseleave') onMouseLeave(){
this.highlightElement(null);
}
15
Angular Development Best Practices
If we have a logic inside child components and we want to execute that logic
as soon as decorator parameters are modified, we can use ngOnChanges()
lifecycle hook.
constructor() { }
ngOnInit() {
this.getAllOwners();
}
}
constructor() { }
ngOnInit() {
this.getAllOwners();
}
}
SERVICES
Let's talk a bit more about services, how to use them, why we should use
them and how to provide them.
16
Angular Development Best Practices
Service Usage
Services provide a great way to connect two unrelated components. To
configure services for this, the best way is to register them is as a singleton.
Furthermore, services are a great way to extract the code from our
components, thus making components more readable and maintainable. We
may use a service to extract the code related to the component in which that
service is provided or to share reusable code with that service between
different components.
Single Responsibility
Services in Angular should be implemented with the single responsibility
principle in mind. Service shouldn’t be responsible for multiple actions or
features. Just the opposite. As soon as we notice that our service starts to
exceed the singular purpose, we should create another service.
Providing Services
If we want to use our service as a singleton, then we should provide that
service at the root of our application. That way Angular creates a single,
shared instance of our service, available for all components.
17
Angular Development Best Practices
Since Angular v6, if we create a service with the Angular CLI command: ng
g service service_name, it will create a service with the providedIn
metadata with the “root” value:
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root',
})
export class HeroService {
constructor() { }
Of course, if we need it, we can do it that way as well. We can register our
service at different levels.
@Component({
selector: 'foo-root',
templateUrl: './foo.component.html',
styleUrls: ['./foo.component.css'],
providers: [ErrorHandlerService]
})
18
Angular Development Best Practices
Or on a module level:
import { TestserviceService } from './testservice.service';
@NgModule({
declarations: [
AppComponent,
HomeComponent
],
imports: [
BrowserModule,
HttpClientModule,
AppRoutingModule
],
providers: [
TestserviceService
],
bootstrap: [AppComponent]
})
export class AppModule { }
HTTP
Let's talk more about HttpClient Module and how to use HTTP requests in our
services.
The way of using the HttpClient library is the same as with the old one. First,
we import it into your app module:
import { HttpClientModule } from '@angular/common/http';
19
Angular Development Best Practices
After that, we need to import it into the service we want to use HttpClient in:
In such cases, we should transfer the HTTP handling responsibility from the
component to the service. We may even create a service as a centralized
place to handle the HTTP requests, and then to use that service in our
application.
20
Angular Development Best Practices
ENVIRONMENT VARIABLES
If we develop an Angular application with a plan to deploy it to production
environment, the environment variables inside the Angular project can be
very helpful. We can set up those variables to distinguish the end-points
between development and production environment.
If you want to learn more about how to use and set up environment
variables in Angular, you can read https://code-maze.com/net-core-web-
development-part9/#environmentFiles.
CONCLUSION
In this guide, we wanted to bring you closer to what the recommendations
while developing our Angular project are.
Thank you for reading the guide and we hope you found something useful in
it.
21