Here’re some set of rules that you need to follow to make your project comply with the standard Angular style guide
- Single Responsibility Principle, check
- Per file, the code must not exceed from 400 lines limit
- Per function, the code must not exceed from 75 lines
- Utilise custom prefix to prevent element name collisions with components in other apps and with native HTML elements.
- If the values of the variables are intact, declare it with const
- Names of properties and methods should be in lower camel case
- Always leave one empty line between imports and module such as third party and application imports and third-party module and custom module
- We shouldn’t name our interfaces with the starting capital I letter as we do in some programming languages.
- Follow naming conventions
- Proper Observable handling, check
- Utilize
index.ts
, check - Proper change detection practice, check
- use trackBy with ngFor, check
- check for public, protected, private modifiers to make an appropiate api for class, funtions, etc
- handle all subscriptions..subsink or rxjs Subscription
- Classes
- UpperCamelCase
- Files i.e
.component.ts
,component.html
,component.scss
,.module.ts
,.pipes.ts
,.routing.ts
- Interfaces
- UpperCamelCase
- suffix with 'I' I.E
UserI
,InstrumentListI
- Observables
- suffix with '$'
- Observalbles vs Promises
It is very important not to create more than one component, service, directive… inside a single file. Every file should be responsible for a single functionality. By doing this, we are keeping our files clean, readable, and maintainable.
While creating files, we should pay attention to the file names.
Names of folders and files should clearly convey their intent. Names should be consistent with the same pattern in which we mention the file’s feature first and then the type, dot separated.
For example consultation.component.ts
or home.component.html
or auth.service.ts
If we want to add more descriptive names to our files we should use a dash(-) to separate the words in the name: tc-home.component.ts
book-appointment.component.ts
When we add names to classes, we should use upper camel case style with the added suffix that represents the type of our file: DatepickerDirective TcHomeComponent AuthService
The Angular CLI is a command-line interface tool that is used to initialize, develop, scaffold, maintain, and even test and debug Angular applications.
ng new
- To create an application that already works, right out of the box.
ng generate
- To Generate components, routes, services and pipes with a simple command with test shells.
ng serve
- To test your app locally while developing.
ng test
- To run your unit tests or end-to-end tests
ng lint
- To make your code shine
ng add
@angular/pwa - To set up the Angular service worker
This interface can be used to create an initial-level structure for the application. It’d be much easier for developers to understand the folder structure and app flow using Angular CLI. Ultimately, it saves hours of developers time.
--app
|-- modules
|-- feature1
|-- [+] components
|-- [+] atoms
# basic element structure
|-- atom1
|-- atoms1.component.ts
|-- atoms1.component.scss //optional, should we move styles to styles dir?
|-- atoms1.component.html
|-- [+] molecules
|-- [+] organisms
|-- [+] pages
|-- [+] templates
|-- [+] core
|-- [+] types
|-- [+] pipes
|-- [+] directives
|-- [+] services
|-- feature1-routing.module.ts
|-- feature1.module.ts
|-- feature1.component.ts
|-- feature1.component.scss //optional, should we move styles to styles dir?
|-- feature1.component.html
|-- feature2
|-- [+] components
|-- [+] core
|-- [+] types
|-- [+] pipes
|-- [+] directives
|-- [+] services
|-- feature2-routing.module.ts
|-- feature2.module.ts
|-- core
|-- [+] components
|-- [+] header
|-- [+] footer
|-- [+] gaurds
|-- [+] interceptors
|-- [+] mocks
|-- [+] services
|-- [+] authentication
|-- core.module.ts
|-- shared
|-- [+] components
|-- [+] directives
|-- [+] pipes
|-- [+] core
|-- [+] types
|-- [+] pipes
|-- [+] directives
|-- [+] configs
|-- assets
|-- styles
|-- [+] partials
|-- _base.scss
|-- styles.scss
They are simple, reusable, and easy to test pieces of code. They both receive @Input and can emit @Ouput. The perfect candidates for UI libraries.
Atoms: The smallest unit possible, reused all over the place. Normally a single HTML element with basic styling. Molecules: A single group of atoms.
In terms of reducing smart components complexity, templates help reducing the HTML boilerplate, and organisms their typescript counterpart. Templates and organisms can help reduce the noise, and keep the code structured and ready to scale. It will be easier to recognize and reuse the pieces of code in future similar-looking features. Widgets. Stand-alone sections of the app that may be reused among multiple pages and have self-contained meaning.
Think of templates as scaffold & skins for a certain component. Just plain HTML-CSS with ng-content. They are used by high order components (like pages or organisms) to take care of style variability and HTML boilerplate. This component shouldn´t have any input, output, logic, or constructor dependencies.
Commonly referred to as features in the classic core/features/shared project structure. Smart components manage input/output connecting with the core of your app vía services.
If we want to create a contract for our class we should always use interfaces. By using them we can force the class to implement functions and properties declared inside the interface.
The best example for this is to have angular life cycle hooks in your component: class HomeComponent implements OnInit
, OnDestroy
Using interfaces is a perfect way of describing our object literals. If our object is an interface type, it is obligated to implement all of the interface’s properties.
export interface UserI {
name: string;
age: number;
address?: string;
};
Objects and arrays are the reference types in javascript. If we want to copy them into another object or an array and to modify them, the best practice is to do that in an immutable way using es6 spread operator(…)
const person: UserI = {
name: 'bob',
age: 40
};
const updatedPerson = {
...person,
name: 'alice'
};
//or
const updatedPerson = Object.assign(person, { name: 'alice'});
To be on the safe side we should always use the safe navigation operator while accessing a property from an object in a component’s template. If the object is null and we try to access a property, we are going to get an exception. But if we use the save navigation (?) operator, the template will ignore the null value and will access the property once the object is not null anymore.
<span>{{ user?.name }} </span>
Observable memory leaks are very common and found in every programming language, library, or framework. Angular is no exception to that. Observables in Angular are very useful as it streamlines your data, but memory leak is one of the very serious issues that might occur if you are not focused. It can create the worst situation in mid of development. Here’re some of the tips which follow to avoid leaks. suffix variable with '$'
const protected state$: Observable<T>;
Using async
pipe
Using take(1)
Using takeUntil()
Unsubsribe from subscriptions in ngOnDestroy
index.ts
helps us to keep all related things together so that we don’t have to be bothered about the source file name. This helps reduce the size of the import statement.
For example, we have article/index.ts
as
export * from './user.model';
export * from './user.config';
export { UserComponent } from './user.component';
We can import all things by using the source folder name.
export { UserComponent, UserConfig } from './user';
- Use NgIf and not CSS - If DOM elements aren’t visible, instead of hiding them with CSS, it's a good practice to remove them from the DOM by using *ngIf.
- Move complex calculations into the ngDoCheck lifecycle hook to make your expressions faster.
- Cache complex calculations as long as possible
- Use the OnPush change detection strategy to tell Angular there have been no changes. This lets you skip the entire change detection step.
If there is a piece of UI that you need in many places in your application, build a component out of it and use the component. This will save you a lot of trouble if, for some reason, the UI has to be changed. In that case, you do not go around changing the UI code in all the places. Instead, you can change the code in the component and that is it.
For this, you may have to use property and event bindings to pass inputs to the components and receive output events from the components, respectively.
When using ngFor to loop over an array in templates, use it with a trackBy function which will return a unique identifier for each DOM item.
When an array changes, Angular re-renders the whole DOM tree. But when you use trackBy, Angular will know which element has changed and will only make DOM changes only for that element.
<ul>
<li> *ngFor="let item of itemList; treackBy: trackByFn"
{{item.id}}
</li>
</ui>
Utilizing lazy load the modules can enhance productivity. Lazy Load is a built-in feature in Angular which helps us with loading the things on demand. When have used LazyLoad it helps in reducing the size of the application by abstaining from unnecessary file from loading. Following are the modules, which are been used in angular apps widely
Multi Modules
Routing Modules
Shared Modules
Lazy Load Modules
Always document the code as much as possible. It will help the new developer involved in a project to understand its logic and readability.
It is a good practice to document each variable and method. For methods, we need to define it using multi-line comments on what task the method performs and all parameters should be explained.
https://blogs.halodoc.io/angular-best-practices/ https://medium.com/weekly-webtips/angular-clean-arquitecture-d40e9c50f51 https://angular.io/guide/styleguide#angular-coding-style-guide
- like adding a styles prop to components for dynamic composable styling
<app-index-trader-weight-molecule
*ngFor="let config of slidersConfigs; let i = index"
[inputConfig]="config"
[styles]="{
label: {
display: 'none'
},
legend: {
display: 'none'
}
}"
(onChange)="templateEventHandler($event)"
></app-index-trader-weight-molecule>