DEV Community

V.D
V.D

Posted on • Originally published at javascript.plainenglish.io on

Angular —Adapter Pattern: Simplify Data Integration(Kanban Board)

Simplifying Integration and Enhancing Flexibility

1

Introduction

A common requirement in modern web development is the integration of data from multiple sources. However, working with various data formats and APIs can be complex, and code can be tightly coupled to specific data sources. To overcome this problem, the adapter pattern provides a solution by acting as a bridge between incompatible interfaces. In this article, we’ll showcase the adapter pattern, using the Kanban board as an example. Will also provide code examples and practical use cases to illustrate the benefits.

Understanding the Adapter Pattern:

The Adapter pattern is a structural design pattern that allows objects with incompatible interfaces to work together. It acts as an intermediary between two incompatible classes, translating requests from one to the other. This pattern provides a way to reuse existing code and promotes loose coupling between components.

The main components of the Adapter pattern are:

  • Target : The interface that the client interacts with.
  • Adaptee : The existing interface that needs to be adapted.
  • Adapter : The bridge between the Target and the Adaptee that implements the Target interface and internally uses the Adaptee to perform the desired operations.

Real world use cases:

To better understand the practical use of the adapter pattern, let’s look at a real world scenario. Imagine building a project management application with Angular and deciding to implement a Kanban board to visualize tasks and progress.

Kanban boards integrate with various task management systems such as Jira, Trello, and Asana, each with its own API and data structure. Without the adapter pattern, you would have to write custom code for each task management system to tightly couple your application to these external services.

However, the adapter pattern allows you to create an adapter for each project task management system by abstracting the details of the underlying API and data structures. This allows you to switch between different task management systems without changing the core logic of your application.

Implementing the Adapter Pattern in Angular:

Now let’s dive into the implementation of the Adapter pattern in an Angular application. We’ll focus on integrating a Kanban board with two different task management systems: Jira and Trello.

  1. Define the Kanban Board Component: First, let’s create the Kanban board component, which will be responsible for rendering the tasks and their corresponding status columns. Here’s a simplified example of the KanbanBoardComponent in Angular:
import { Component, OnInit } from '@angular/core';
import { Task } from './task.interface';
import { TaskManagementAdapter } from './task-management-adapter';

@Component({
  selector: 'app-kanban-board',
  template: `
    <div class="kanban-board">
      <div class="column" *ngFor="let statusColumn of statusColumns">
        <h2>{{ statusColumn }}</h2>
        <div class="task" *ngFor="let task of getTasksByStatus(statusColumn)">
          {{ task.title }}
        </div>
      </div>
    </div>
  `,
  styleUrls: ['./kanban-board.component.css']
})
export class KanbanBoardComponent implements OnInit {
  statusColumns: string[] = ['To Do', 'In Progress', 'Done'];
  tasks: Task[] = [];
  taskManagementAdapter: TaskManagementAdapter;

  constructor(private adapter: TaskManagementAdapter) {
    this.taskManagementAdapter = adapter;
  }

  ngOnInit(): void {
    this.loadTasks();
  }

  loadTasks(): void {
    this.tasks = this.taskManagementAdapter.getTasks();
  }

  getTasksByStatus(status: string): Task[] {
    return this.tasks.filter(task => task.status === status);
  }
}
Enter fullscreen mode Exit fullscreen mode

2. Create the Task Interface and Adapters:

Next, let’s define the Task interface, which represents a task on the Kanban board. We’ll also create adapters for Jira and Trello, implementing the TaskManagementAdapter interface. Here’s an example:

export interface Task {
  id: number;
  title: string;
  status

: string;
}

export interface TaskManagementAdapter {
  getTasks(): Task[];
}

export class JiraAdapter implements TaskManagementAdapter {
  getTasks(): Task[] {
    // Implement Jira-specific logic to fetch tasks
    // and map them to the Task interface
  }
}

export class TrelloAdapter implements TaskManagementAdapter {
  getTasks(): Task[] {
    // Implement Trello-specific logic to fetch tasks
    // and map them to the Task interface
  }
}
Enter fullscreen mode Exit fullscreen mode

3. Implement the Adapters:

Now, it’s time to implement the JiraAdapter and TrelloAdapter. These adapters encapsulate the logic of interacting with the respective task management systems’ APIs and converting the data into the Task interface format. Here’s a simplified example:

export class JiraAdapter implements TaskManagementAdapter {
  getTasks(): Task[] {
    // Use Jira API to fetch tasks
    // Convert and map the fetched data to the Task interface format
    return jiraAPI.getTasks().map(task => ({
      id: task.id,
      title: task.name,
      status: task.status
    }));
  }
}

export class TrelloAdapter implements TaskManagementAdapter {
  getTasks(): Task[] {
    // Use Trello API to fetch tasks
    // Convert and map the fetched data to the Task interface format
    return trelloAPI.getTasks().map(task => ({
      id: task.id,
      title: task.title,
      status: task.status
    }));
  }
}
Enter fullscreen mode Exit fullscreen mode

4. Wiring Everything Together:

Finally, we need to provide the appropriate adapter to the KanbanBoardComponent. In your Angular module, you can configure the dependency injection to provide the desired adapter. Here’s an example using the JiraAdapter:

// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent } from './app.component';
import { KanbanBoardComponent } from './kanban-board/kanban-board.component';
import { TaskManagementSystemAdapter } from './adapters/task-management-system.adapter';
import { JiraAdapter } from './adapters/jira.adapter';
import { TrelloAdapter } from './adapters/trello.adapter';

@NgModule({
  declarations: [
    AppComponent,
    KanbanBoardComponent
  ],
  imports: [
    BrowserModule
  ],
  providers: [
    { provide: TaskManagementSystemAdapter, useClass: JiraAdapter }, // Using JiraAdapter
    { provide: TaskManagementSystemAdapter, useClass: TrelloAdapter } // Using TrelloAdapter
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }
Enter fullscreen mode Exit fullscreen mode

Explanation

In the above code, both the JiraAdapter and the TrelloAdapter are provided as implementations for the TaskManagementSystemAdapter token. By doing this, Angular’s dependency injection will be able to inject the appropriate adapter based on the context.

Now, when the KanbanBoardComponent is instantiated, Angular will inject both the JiraAdapter and the TrelloAdapter as separate instances of the TaskManagementSystemAdapter. You can then use these adapters based on your specific requirements within the KanbanBoardComponent.

This approach allows you to integrate and work with multiple task management systems simultaneously within your K anban board application. You can handle different tasks and operations with each adapter , providing a comprehensive solution that caters to diverse needs.

// kanban-board.component.ts
import { Component, OnInit } from '@angular/core';
import { TaskManagementSystemAdapter } from '../adapters/task-management-system.adapter';

@Component({
  selector: 'app-kanban-board',
  templateUrl: './kanban-board.component.html',
  styleUrls: ['./kanban-board.component.css']
})
export class KanbanBoardComponent implements OnInit {
  tasks: string[] = [];

  constructor(
    private jiraAdapter: TaskManagementSystemAdapter,
    private trelloAdapter: TaskManagementSystemAdapter
  ) {}

  ngOnInit() {
    this.loadTasks();
  }

  loadTasks() {
    // Use the JiraAdapter to fetch tasks from Jira
    const jiraTasks = this.jiraAdapter.getTasks();
    this.tasks.push(...jiraTasks);

    // Use the TrelloAdapter to fetch tasks from Trello
    const trelloTasks = this.trelloAdapter.getTasks();
    this.tasks.push(...trelloTasks);
  }

  addTask(task: string) {
    // Use the JiraAdapter to create a new task in Jira
    this.jiraAdapter.createTask(task);

    // Use the TrelloAdapter to create a new task in Trello
    this.trelloAdapter.createTask(task);
  }

  removeTask(index: number) {
    this.tasks.splice(index, 1);
  }
}
Enter fullscreen mode Exit fullscreen mode

Explanation

In the above code, the KanbanBoardComponent has two dependencies injected: jiraAdapter of type TaskManagementSystemAdapter and trelloAdapter of type TaskManagementSystemAdapter. These dependencies are provided by the AppModule , where we configured the dependency injection to use both the JiraAdapter and the TrelloAdapter.

The addTask method allows you to create a new task. Using the jiraAdapter and trelloAdapter , we can call the createTask method on each adapter to create the task in both Jira and Trello simultaneously.

The removeTask method removes a task from the tasks array when it is completed or deleted, as per your implementation.

By using both adapters in the KanbanBoardComponent , you can seamlessly integrate and work with multiple task management systems, such as Jira and Trello, within the same Kanban board application. This provides the flexibility to manage tasks across different platforms without writing separate code for each system.

Furthermore, the Adapter pattern promotes a modular and extensible architecture. We can extend our application to support additional task management systems simply by creating new adapters that adhere to the TaskManagementAdapter interface. This flexibility is especially beneficial in scenarios where we may need to integrate multiple external systems or switch between different providers over time.

Conclusion

By applying the Adapter pattern in our Angular application , we have successfully decoupled the Kanban board component from s pecific task management systems. The adapters act as intermediaries, enabling seamless integration with different APIs and data structures. This approach promotes code reusability, flexibility, and maintainability.

The Adapter pattern is a powerful tool in Angular development when dealing with disparate data sources. Whether you’re integrating with external APIs, databases, or other systems, the Adapter pattern provides an elegant solution to manage the complexities of data integration.

Start incorporating this pattern into your angular projects and experience the benefits firsthand. Happy coding!

Thanks for reading


Top comments (0)