Best Practices Folder Structure In Angular

Best Practices Folder Structure In Angular

In this article, we will learn how to organize an Angular Application's folder structure. It's critical to choose the correct folder structure for your real-world Angular application. If you don't have the right structure in place, finding a specific component or file gets increasingly difficult as your App grows in features.

Folder for each Angular Module

To gather together relevant functionalities, Angular employs the concept of Angular Modules. This offers us a good place to begin organizing the folder structure. Each Module should have its own folder with the same name as the Module.

The Angular framework does not distinguish between Modules. However, we may categorize our modules into the four categories below based on how we use them.

  1. Root Module
  2. Feature Module
  3. Shared Module
  4. Core Module

Root Module

As soon as the application starts, one module must be loaded. This is referred to as the root module. The root module is responsible for loading the root component as well as all other modules.

The root module is usually referred to as AppModule and is located in the /src/app.folder.

Feature Modules

The Features module implements a certain application feature. The module contains all of the components, pipes, and directives that implement the feature.

Feature Modules require all components to be stored in a directory named after the module. /src/app/ModuleName>, for example. We make it easier to find a component that belongs to the module by doing so.

Under the module folder, you can build subfolders for directives and pipes.

You can make a components folder in which you can store all of your components. Alternatively, within the components folder, create a subdirectory for each component.

Another way to make a page folder is to use a text editor. Each route is represented by a page. The route path is used to name the folder. There could be more than one component in the route. They're all in the same page folder. The shared components should go in the separate components folder.

├── src
│   ├── app
│   │   ├── admin 
│   │   │   ├── components
│   │   │   │   ├── shared.component.ts
│   │   │   ├── directives
│   │   │   │   ├── first.directive.ts
│   │   │   │   ├── another.directive.ts
│   │   │   ├── pages
│   │   │   │   ├── dashboard
│   │   │   │   │   ├── dashboard.component.ts
│   │   │   │   ├── rights
│   │   │   │   │   ├── rights.component.ts
│   │   │   │   ├── user
│   │   │   │   │   ├── user.component.ts
│   │   │   │   ├── admin.component.ts
│   │   │   │   ├── admin.component.html
│   │   │   │   ├── admin.component.css
│   │   │   │   ├── index.ts
│   │   │   ├── pipes
│   │   │   │   ├── first.pipe.ts
│   │   │   │   ├── another.pipe.ts
│   │   │   ├── admin.module.ts
│   │   │   ├── admin.routing.module.ts
│   │   │   ├── index.ts

Shared Module

There are a number of components, directives, and pipelines that we'd like to share between modules. All of these elements should be placed in the shared module.

The shared module must use the declarations metadata to declare the components, pipes, and directives, and export them using the exports metadata.

Other modules can use the exported components, directives, and pipes by importing the shared modules.

It is not necessary to specify the Services at this time. Because shared modules are imported everywhere, if it is imported in the lazy loaded modules, it may build a new instance of the service.

The Shared module must be placed in the /src/app/shared directory.

There should be no dependencies between the Shared module and any of the other modules in the application.

Commonly used angular modules (CommonModule, FormsModule, and so on), as well as third-party modules, can be imported and re-exported here. Those modules are not required to be imported by the other module that imports the shared module.

You can use the folder structure below, in which each shared feature is created in its own folder.

├── src
│   ├── app
│   │   ├── shared
│   │   │   ├── layout
│   │   │   │   ├── footer
│   │   │   │   │   ├── footer.component.ts
│   │   │   │   │   ├── footer.component.html
│   │   │   │   ├── header
│   │   │   │   │   ├── header.component.ts
│   │   │   │   │   ├── header.component.html
│   │   │   ├── index.ts

Alternatively, as seen below, you can create directories such as components, pipelines, and directives.

├── src
│   ├── app
│   │   ├── shared
│   │   │   ├── components
│   │   │   │   ├── footer
│   │   │   │   │   ├── footer.component.ts
│   │   │   │   │   ├── footer.component.html
│   │   │   │   ├── header
│   │   │   │   │   ├── header.component.ts
│   │   │   │   │   ├── header.component.html
│   │   │   ├── pipes
│   │   │   │   ├── pipe1
│   │   │   │   │   ├── pipe1.pipe.ts
│   │   │   ├── index.ts

Core Module

The CoreModule must include all of the application's shared services. User authentication services and data retrieval services are examples of such services.

A Singleton Service is one in which only one instance of the Service exists. The fact that it's in CoreModule assures that the services are singletons.

Only the root module must import the core module. The core modules must not be imported by other modules. To prevent other modules from importing the core module, use the code below.

@NgModule({})
export class CoreModule { 
 
  constructor(@Optional() @SkipSelf() core:CoreModule ){
    if (core) {
        throw new Error("You should import core module only in the root module")
    }
  }
}

The CoreModule should be placed in the /src/app/core subdirectory.

You can create subfolders for each service under the services folder under the core folder.

Folder Structure Example 

Let's make a simple module that includes a shared, core, and feature module.

Using ng new, create a new application.

ng new --routing  --style css ModuleDemo

Feature Modules

Let's make three feature modules now. GthubModule, AdminModule, and HomeModule

Admin Module

Make an admin folder in the /src/app directory.

Create the admin.module.ts file in the /src/app/admin folder.

Add the following code under the admin.module.ts file:

import { NgModule } from '@angular/core';
import { AdminRoutingModule } from './admin.routing.module';
import { UserComponent,RightsComponent,DashboardComponent, AdminComponent } from './pages';
 
@NgModule({
  declarations: [UserComponent,RightsComponent,DashboardComponent,AdminComponent],
  imports: [
    AdminRoutingModule,
  ],
  providers: [],
})
export class AdminModule { }

Add the following code under the admin.routing.module.ts file:

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
 
import { UserComponent , RightsComponent ,DashboardComponent, AdminComponent } from './pages';
 
const routes: Routes = [
    {   path: 'admin', component: AdminComponent,
        children :[
            { path: 'dashboard', component: DashboardComponent},
            { path: 'user', component: UserComponent},
            { path: 'rights', component: RightsComponent},
        ]
    },
];
 
@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})
export class AdminRoutingModule { }

There are four pages in the AdminModule module. The root page is an admin page. It can be found in the pages folder.

Add the following code under the admin.component.ts file:

import { Component} from '@angular/core';
 
@Component({
  selector: 'app-admin',
  templateUrl: './admin.component.html',
  styleUrls: ['./admin.component.css']
})
export class AdminComponent  {
}

Add the following code under the admin.component.html file:

<ul>
  <li><a routerlink="dashboard">dashboard</a></li>
  <li><a routerlink="user">User</a></li>
  <li><a routerlink="rights">Rights</a></li>
</ul>
<router-outlet></router-outlet>

There are three pages beneath the admin page. dashboard, rights & user. As a result, beneath the pages folder, create a subfolder for all of these.

Add the following code under the /app/src/admin/pages/dashboard/dashboard.component.ts.

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

@Component({
  template: `<h1>Dashboard Component</h1>`,
})
export class DashboardComponent {
  title = '';
}

Add the following code under the /app/src/admin/pages/rights/rights.component.ts.

import { Component } from '@angular/core';
 
@Component({
  template: '<h1>Rights Component</h1>',
})
export class RightsComponent {
  title = '';
}

Add the following code under the /app/src/admin/pages/user/user.component.ts.

import { Component } from '@angular/core';
 
@Component({
  template: '<h1>User Component</h1>',
})
export class UserComponent {
  title = '';
}

Add the following code under the /app/src/admin/pages/index.ts.

export * from './dashboard/dashboard.component';
export * from './rights/rights.component';
export * from './user/user.component';
export * from './admin.component';

Add the following code under the /app/src/admin/index.ts.

export * from './pages';
export * from './github.module';

Github Module

The GithubModule gets a list of repository from a specific user's GitHub repository. The module is saved in the github folder. The components are stored in the pages folder.

Add the following code under the /app/src/github/pages/list/repo-list.component.ts.

import { Component } from '@angular/core';
import { Observable } from 'rxjs';
 
import { GitHubService } from '../../../core';
import { repos} from '../../../core';
 
@Component({
    templateUrl: './repo-list.component.html',
})
export class RepoListComponent
{
    userName: string ="angular"
    repos: repos[];
 
    loading: boolean=false;
    errorMessage;
 
    constructor(private githubService: GitHubService) {
    }
 
    public getRepos() {
        this.loading=true;
        this.errorMessage="";
        this.githubService.getRepos(this.userName)
            .subscribe((response) =&gt; {this.repos=response;},
            (error) =&gt; {this.errorMessage=error; this.loading=false; },
            () =&gt; {this.loading=false;})
    }
}

Add the following code under the /app/src/github/pages/list/repo-list.component.html:

<h1 class="heading"><strong>HTTP </strong>Demo</h1>
 
<div class="form-group">
    <label>GitHub User Name</label>
    <input class="form-control" name="userName" ngmodel="" type="text" username="" />
</div>
 
<div class="form-group">
    <button click="" getrepos="" type="button">Get Repos</button>
</div>
 
<div ngif="loading">loading...</div>
 
<div class="alert alert-warning" ngif="errorMessage">
    <strong>Warning!</strong> {{errorMessage}}
</div>
 
<div class="table-responsive">
    <table class="table">
    <thead>
    <tr>
        <th>ID</th>
        <th>Name</th>
        <th>HTML Url</th>
        <th>description</th>
    </tr>
</thead>
<tbody>
    <tr ngfor="let repo of repos;">
        <td>{{repo.id}}</td>
        <td>{{repo.name}}</td>
        <td>{{repo.html_url}}</td>
        <td>{{repo.description}}</td>
    </tr>
</tbody>
</table>
</div>

Add the following code under the /app/src/github/pages/index.ts:

export * from './repolist/repo-list.component';

Add the following code under the /app/src/github/github-routing.module.ts:

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { RepoListComponent } from './pages';
 
const routes: Routes = [
  {   path: 'github',  component: RepoListComponent,
        children :[
          { path: 'list', component: RepoListComponent},
        ]
  }
];
 
@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})
export class GithubRoutingModule {}

Add the following code under the /app/src/github/github.module.ts:

import { NgModule } from '@angular/core';
import { GithubRoutingModule } from './github-routing.module';
 
import { RepoListComponent } from './pages';
 
import { SharedModule } from '../shared';
 
@NgModule({
  imports: [
    GithubRoutingModule,SharedModule
  ],
  providers: [
  ],
  declarations: [RepoListComponent]
})
export class GithubModule { }

Add the following code under the /app/src/github/index.ts:

export * from './pages';
export * from './github.module';

Home Module

HomeComponent, ContactUsComponent, and AboutUsComponent are the three components in this module.

Add the following code under the src/app/home/pages/about-us.component.ts:

import { Component } from '@angular/core';
 
@Component({
    template: `Anout Us`,
})
export class AboutUsComponent
{
}

Add the following code under the src/app/home/pages/contact-us.component.ts:

import { Component } from '@angular/core';
 
@Component({
    template: `Contact Us`,
})
export class ContactUsComponent
{
}

Add the following code under the src/app/home/pages/home.component.ts:

import { Component } from '@angular/core';
 
@Component({
    template: `<h1> Welcome To Module Demo</h1>`,
})
export class HomeComponent
{
}

Add the following code under the src/app/home/pages/index.ts:

export * from './aboutus/about-us.component';
export * from './contactus/contact-us.component';
export * from './home/home.component';

Add the following code under the src/app/home/home-routing.module.ts:

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AboutUsComponent,ContactUsComponent,HomeComponent } from './pages';
 
const routes: Routes = [
  { path: '',   component: HomeComponent},
  { path: 'contactus', component: ContactUsComponent},
  { path: 'aboutus', component: AboutUsComponent},
];
 
 
@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})
export class HomeRoutingModule {}

Add the following code under the src/app/home/home.module.ts:

import { NgModule } from '@angular/core';
import { HomeRoutingModule } from './home-routing.module';
 
import { AboutUsComponent,ContactUsComponent,HomeComponent } from './pages';
 
import { SharedModule } from '../shared';
 
@NgModule({
  imports: [
    HomeRoutingModule,SharedModule
  ],
  providers: [
  ],
  declarations: [AboutUsComponent,ContactUsComponent,HomeComponent]
})
export class HomeModule { 
 
}

Add the following code under the src/app/home/index.ts:

export * from './pages';
export * from './home.module';

Core Module

Application-wide singleton services are contained in the CoreModule. In this sample project, there is a GitHubService that retrieves a user's list of repositories. The CoreModule is built in the src/app/core subdirectory.

The src/app/core/services subdirectory is where all services are generated. You can also separate each service into its own folder.

Add the following code under the src/app/core/models/repos.ts:

export class repos {
    id: string;
    name: string;
    html_url: string;
    description: string;
}

Add the following code under the src/app/core/models/index.ts:

export * from './repos';

Add the following code under the src/app/core/models/services/github.service.ts:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
 
import { repos} from '../models';
 
@Injectable()
export class GitHubService { 
   baseURL:string="https://api.github.com/";
 
   constructor(private http:HttpClient){
   }
 
   getRepos(userName:string): Observable<repos> {
        return this.http.get<repos>(this.baseURL + 'users/' + userName + '/repos')
   }
}

Add the following code under the src/app/core/models/services/index.ts:

export * from './github.service';

Add the following code under the src/app/core/models/core.module.ts:

import { NgModule, Optional, SkipSelf } from '@angular/core';
import {  GitHubService  } from './services/github.service';
 
@NgModule({
  imports: [
  ],
  providers: [
    GitHubService
  ],
  declarations: []
})
export class CoreModule { 
 
  constructor(@Optional() @SkipSelf() core:CoreModule ){
    if (core) {
        throw new Error("You should import core module only in the root module")
    }
  }
}

Add the following code under the src/app/core/models/index.ts:

export * from './core.module';
export * from './services';
export * from './models';

Shared Module

HeaderComponent and FooterComponent, which are used by the root module, are included in our Shared Module.

Add the following code under the /src/app/shared/layout/footer/footer.component.html:

<p>(c) All Rights Reserved</p>

Add the following code under the /src/app/shared/layout/footer/footer.component.ts:

import { Component } from '@angular/core';
 
@Component({
  selector: 'app-footer',
  templateUrl: './footer.component.html'
})
export class FooterComponent {
}

Add the following code under the /src/app/shared/layout/header/header.component.html:

<ul>
    <li>
      <a class="navbar-brand" routerlink="/">home</a>
    </li>
    <li>
      <a class="navbar-brand" routerlink="/github/list">GitHub</a>
    </li>
    <li>
      <a class="navbar-brand" routerlink="/admin">Admin</a>
    </li>
    <li>
      <a class="navbar-brand" routerlink="/aboutus">About</a>
  </li>
  <li>
    <a class="navbar-brand" routerlink="/contactus">Contact</a>
  </li>
  
</ul>

Add the following code under the /src/app/layout/header/header.component.css:

ul {
    list-style-type: none;
    margin: 0;
    padding: 0;
    overflow: hidden;
    background-color: #333333;
}
 
li {
    float: left;
}
 
li a {
    display: block;
    color: white;
    text-align: center;
    padding: 16px;
    text-decoration: none;
}
 
li a:hover {
    background-color: #111111;
}

Add the following code under the /src/app/layout/header/header.component.ts:

import { Component, OnInit } from '@angular/core';
 
@Component({
  selector: 'app-header',
  templateUrl: './header.component.html',
  styleUrls: ['./header.component.css']
})
export class HeaderComponent {
}

Add the following code under the /src/app/layout/index.ts:

export * from './footer/footer.component';
export * from './header/header.component';

Add the following code under the /src/app/shared/shared.module.ts:

import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import { RouterModule } from '@angular/router';
import { HeaderComponent, FooterComponent } from './layout';
 
 
@NgModule({
  imports: [
    CommonModule,
    FormsModule,
    ReactiveFormsModule,
    HttpClientModule,
    RouterModule
  ],
  declarations: [ HeaderComponent,FooterComponent ],
  exports: [
    CommonModule,
    FormsModule,
    ReactiveFormsModule,
    HttpClientModule,
    RouterModule,
    HeaderComponent,FooterComponent
  ]
})
export class SharedModule {
}

Add the following code under the /src/app/shared/index.ts:

export * from './shared.module';
export * from './layout';

Final Folder Structure

The following table depicts our application's final structure. You can adjust/fine-tune them according to your project's needs.

├── src
│   ├── app
│   │   ├── admin 
│   │   │   ├── directives
│   │   │   ├── pages
│   │   │   │   ├── dashboard
│   │   │   │   │   ├── dashboard.component.ts
│   │   │   │   ├── rights
│   │   │   │   │   ├── rights.component.ts
│   │   │   │   ├── user
│   │   │   │   │   ├── user.component.ts
│   │   │   │   ├── admin.component.ts
│   │   │   │   ├── admin.component.html
│   │   │   │   ├── admin.component.css
│   │   │   │   ├── index.ts
│   │   │   ├── pipes
│   │   │   ├── admin.module.ts
│   │   │   ├── admin.routing.module.ts
│   │   │   ├── index.ts
│   │   ├── core
│   │   │   ├── models
│   │   │   │   ├── index.ts
│   │   │   │   ├── repos.ts
│   │   │   ├── services
│   │   │   │   ├── github.service.ts
│   │   │   │   ├── index.ts
│   │   │   ├── core.module.ts
│   │   │   ├── index.ts
│   │   ├── github
│   │   │   ├── pages
│   │   │   │   ├── repolist
│   │   │   │   │   ├── repolist.component.ts
│   │   │   │   │   ├── repolist.component.html
│   │   │   ├── github.routing.module.ts
│   │   │   ├── github.module.ts
│   │   │   ├── index.ts
│   │   ├── home
│   │   │   ├── pages
│   │   │   │   ├── aboutus
│   │   │   │   │   ├── about-us.component.ts
│   │   │   │   ├── contactus
│   │   │   │   │   ├── contact-us.component.ts
│   │   │   │   ├── home
│   │   │   │   │   ├── home-us.component.ts
│   │   │   │   ├── index.ts
│   │   │   ├── home-routing.module.ts
│   │   │   ├── home.module.ts
│   │   │   ├── index.ts
│   │   ├── shared
│   │   │   ├── layout
│   │   │   │   ├── footer
│   │   │   │   │   ├── footer.component.ts
│   │   │   │   │   ├── footer.component.html
│   │   │   │   ├── header
│   │   │   │   │   ├── header.component.ts
│   │   │   │   │   ├── header.component.html
│   │   │   ├── index.ts
│   ├── app-routing.module.ts  
│   ├── app-wildcard-routing.module.ts
│   ├── app.component.css
│   ├── app.component.html
│   ├── app.component.spec.ts
│   ├── app.component.ts
│   ├── app.module.ts
│   ├── not-found.component.ts

Conclusion

In this article, we learned how to organize an Angular Application's folder structure.

I hope this article helps you and you will like it.👍

If you have any doubt or confusion then free to ask in the comment section.

Post a Comment

Previous Post Next Post