Cory Rylan

My name is , Google Developer Expert, Speaker, Software Developer. Building Design Systems and Web Components.

Follow @coryrylan
Angular

Angular Design Patterns: Feature Services

Cory Rylan

- 3 minutes

Updated

This article has been updated to the latest version Angular 17 and tested with Angular 16. The content is likely still applicable for all Angular 2 + versions.

This short post we will cover a design pattern called Feature Services. In a previous post we discussed the Feature/Presentation design pattern. This post will continue to expand on this idea.

When using Feature and Presentation components its common for the Feature component to inject several different services the pull together the data needed for the feature and expose any methods need to save or process data.

The Feature Service design pattern is a way to pull out all of this feature logic from our Feature Component into a single Feature Service. The Feature Service is a Singleton Service that is Injected at the Feature Component level in the component provider. This ensures that the Feature Service is only instantiated once for the Feature Component.

With Angular applications its common that our data will be exposed via RxJS Observables from either API endpoints or NgRx state management. We pull this logic into our Feature Service, so our Feature Component is unaware of where to get the data or how to save it. We have thoroughly encapsulated all of the logic of our feature into a single class.

Benefits of the Feature Service

What does this get us? Well, a few things. First, our Feature Component typically will only need to inject a single Service into its constructor. This, in turn, makes it much easier to test our component as we don't have to stub or mock out many dependencies. Our Feature Component is very clear and easy to understand. For example, let's take a look at this Employee Report Feature Component.

@Component({
  selector: 'app-employee-report',
  templateUrl: 'employee-report.component.html',
  stylesUrl: 'employee-report.component.css',
  providers: [EmployeeReportService]
})
class EmployeeReportComponent {
  employees: Observable<Employee[]>;
  reports: Observable<Reports[]>;

  constructor(private employeeReportService: EmployeeReportService) {}

  ngOnInit() {
    this.employees = this.employeeReportService.employees;
    this.reports = this.employeeReportService.reports;
  }

  saveEmployee(employee: Employee) {
    this.employeeReportService.updateEmployee(employee);
  }

  removeEmployee(employee: Employee) {
    this.employeeReportService.removeEmployee(employee);
  }

  sortByName() {
    this.employeeReportService.sortByName();
  }

  sortReportsByDateCreated() {
    this.employeeReportService.sortReportsByDateCreated();
  }
}

Our component is small and lightweight. It's very apparent what our feature is trying to accomplish. Our data comes from a single source of truth which is our Feature Service. Interactions with that data are all passed through the Feature Service as well. This pattern is suited well for large features or features with many different data resources.

With a combination of Feature Components and Feature Services, we get an architecture like below.

Angular Feature Services

Abstracting everything into a Feature Service is not a strict rule. While we try to keep as much of the high-level feature logic at the feature service, there are exceptions. Services like ElementRef and FormBuilder must be injected into the component. This is ok. We are separating the component view logic from the feature logic.

While the Feature Service has some excellent benefits, there are downsides. If your feature is relatively simple, this can be an over abstraction. This also creates additional boilerplate code with component methods mapping to a service method.

With all design patterns they have pros and cons. We at Vintage Software have found this pattern to work really well on large scale Angular applications in combination with Feature Components.

Twitter Facebook LinkedIn Email
 

No spam. Short occasional updates on Web Development articles, videos, and new courses in your inbox.

Related Posts

Angular

Creating Dynamic Tables in Angular

Learn how to easily create HTML tables in Angular from dynamic data sources.

Read Article
Web Components

Reusable Component Patterns - Default Slots

Learn about how to use default slots in Web Components for a more flexible API design.

Read Article
Web Components

Reusable Component Anti-Patterns - Semantic Obfuscation

Learn about UI Component API design and one of the common anti-patterns, Semantic Obfuscation.

Read Article