Hone logo
Hone
Problems

Angular Shared Modules: Centralizing Common Functionality

In Angular applications, it's common to have modules that provide reusable components, services, or directives used across multiple other modules. Instead of duplicating this code, Angular's module system allows us to create "shared modules" to centralize these common dependencies, promoting code reusability, maintainability, and consistency.

Problem Description

Your task is to create a reusable Angular shared module that encapsulates a common set of functionalities. This shared module will then be imported by other feature modules within an Angular application.

What needs to be achieved:

  1. Create a Shared Module: Define an Angular module named SharedModule.
  2. Declare Common Components/Directives: This module should declare and export a few common components and directives that can be used by any module that imports SharedModule.
  3. Provide Common Services: This module should provide services that are intended to be singletons across the application, accessible by modules that import SharedModule.
  4. Import and Utilize: Demonstrate how another feature module (e.g., AppModule or a hypothetical UserModule) would import and utilize the components, directives, and services from the SharedModule.

Key requirements:

  • The SharedModule should be a standalone Angular module (not a feature module that relies on routing).
  • Any components or directives declared in SharedModule must also be exported from it.
  • Any services provided in SharedModule should be configured to be singletons.

Expected behavior:

  • When SharedModule is imported by another module, the exported components, directives, and services should be directly usable within that importing module's components and templates.
  • Services provided in SharedModule should behave as singletons, meaning only one instance of the service is created and shared across all modules that import SharedModule.

Important edge cases to consider:

  • Circular Dependencies: Ensure the structure doesn't inadvertently create circular dependencies between modules.
  • Service Scope: Understand how providedIn: 'root' or providing in the SharedModule itself affects service instantiation. For this challenge, providing services within SharedModule to demonstrate its capability is the goal.

Examples

Example 1: Component Usage

Input:

  • A SharedModule declares and exports a HighlightDirective.
  • A FeatureModule imports SharedModule.
  • A component within FeatureModule uses the HighlightDirective in its template.

Output (Conceptual - demonstrating usage):

Imagine a HighlightDirective that changes the background color of an element.

In shared.module.ts:

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { HighlightDirective } from './highlight.directive'; // Assume this exists

@NgModule({
  declarations: [
    HighlightDirective
  ],
  imports: [
    CommonModule
  ],
  exports: [
    HighlightDirective // Crucial for external use
  ]
})
export class SharedModule { }

In feature.component.html (within a module that imports SharedModule):

<p appHighlight>This text will be highlighted.</p>

Explanation: The HighlightDirective is declared and exported by SharedModule. When SharedModule is imported by FeatureModule, Angular makes the HighlightDirective available for use in templates of components within FeatureModule.

Example 2: Service Usage

Input:

  • A SharedModule provides a LoggerService.
  • An AppModule imports SharedModule and injects LoggerService into a component.
  • A UserModule (also imports SharedModule) injects LoggerService into a component.

Output (Conceptual - demonstrating service injection and singleton behavior):

In shared.module.ts:

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { LoggerService } from './logger.service'; // Assume this exists

@NgModule({
  declarations: [],
  imports: [
    CommonModule
  ],
  providers: [
    LoggerService // Providing the service here
  ],
  exports: [] // No exports needed for services if just providing
})
export class SharedModule { }

In app.component.ts (within AppModule):

import { Component } from '@angular/core';
import { LoggerService } from './shared/logger.service'; // Path will vary

@Component({
  selector: 'app-root',
  template: '...'
})
export class AppComponent {
  constructor(private logger: LoggerService) {
    this.logger.log('App component initialized.');
  }
}

In user.component.ts (within a module that imports SharedModule):

import { Component } from '@angular/core';
import { LoggerService } from './shared/logger.service'; // Path will vary

@Component({
  selector: 'app-user',
  template: '...'
})
export class UserComponent {
  constructor(private logger: LoggerService) {
    this.logger.log('User component initialized.');
  }
}

Explanation: LoggerService is provided by SharedModule. When AppModule and UserModule import SharedModule, they gain access to LoggerService. Because LoggerService is provided within SharedModule, Angular treats it as a singleton for all modules that depend on SharedModule. Both AppComponent and UserComponent will receive the same instance of LoggerService.

Constraints

  • The Angular version used for this challenge is >= 10.
  • The solution should be written entirely in TypeScript.
  • No third-party libraries beyond Angular's core framework should be used.
  • The SharedModule should not have its own routing configuration.

Notes

  • Consider creating simple placeholder components, directives, and services to fulfill the requirements. For example, a ButtonComponent, a DisableDirective, and a SharedDataService.
  • Think about where to declare and export your shared items. For components and directives, declarations and exports are key. For services, the providers array is used.
  • How do you make a service a singleton when providing it in a module? Consider the providedIn property or simply providing it within the module itself. For this challenge, providing it directly in the SharedModule's providers array is a good way to demonstrate the concept within the module's scope.
  • The goal is to understand the modular structure and how imports and exports facilitate code sharing.
Loading editor...
typescript