Skip to content

Instantly share code, notes, and snippets.

@dragontheory
Created March 20, 2025 19:25
Show Gist options
  • Select an option

  • Save dragontheory/e6eb202d1a9c910716784453cc7213c7 to your computer and use it in GitHub Desktop.

Select an option

Save dragontheory/e6eb202d1a9c910716784453cc7213c7 to your computer and use it in GitHub Desktop.

Decoupling the Presentation Layer in Angular, Vue, and React πŸš€

Objective 🎯

Modern web applications can separate concerns by decoupling the UI (HTML, CSS, JS) from the data and business logic managed by Angular, Vue, or React. This architecture enables design-driven development where front-end developers control UI/UX while developers manage the app’s logic via APIs.


Why Separate the UI from the Data Layer? ❓

  1. 🎨 Design Flexibility: Front-end developers can build UI freely without framework constraints.
  2. πŸ› οΈ Maintainability: UI and business logic can be updated independently.
  3. ⚑ Performance: Eliminates unnecessary re-renders by reducing framework involvement in UI rendering.
  4. πŸ“ˆ Scalability: APIs become reusable across different platforms (web, mobile, other frontends).

How It Works πŸ—οΈ

1. The UI Layer (Vanilla HTML, CSS, JS) 🎨

  • πŸ“„ Static HTML templates serve as the view layer.
  • 🎭 Modern CSS manages styles and responsiveness.
  • πŸ”„ JavaScript fetches data via an API and updates the UI dynamically.

2. The Data & Business Logic Layer (Angular, Vue, React) βš™οΈ

  • Frameworks are used solely for managing data, business rules, and API interactions.
  • The UI is updated dynamically via API calls.

Implementation in Angular, Vue, and React πŸ’»

Each example fetches data via an API and injects it into a vanilla HTML file.


Angular Implementation πŸ…°οΈ

Using Angular Services for data handling while keeping UI separate.

1. Vanilla HTML for UI πŸ“„

<!-- index.html -->
<table id="ipTable">
  <thead>
    <tr>
      <th>IP Address</th>
      <th>Status</th>
    </tr>
  </thead>
  <tbody></tbody>
</table>

<script>
  fetch('https://67d944ca00348dd3e2aa65f4.mockapi.io/ip-addresses')
    .then(response => response.json())
    .then(data => {
      const tbody = document.querySelector("#ipTable tbody");
      tbody.innerHTML = data.map(ip => `<tr><td>${ip.address}</td><td>${ip.status}</td></tr>`).join("");
    });
</script>

2. Angular Service for Data Handling πŸ”—

// src/app/services/ip.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable({ providedIn: 'root' })
export class IpService {
  private apiUrl = 'https://67d944ca00348dd3e2aa65f4.mockapi.io/ip-addresses';
  constructor(private http: HttpClient) {}

  getIpAddresses(): Observable<any> {
    return this.http.get(this.apiUrl);
  }
}

3. Angular Component for API Logic πŸŽ›οΈ

// src/app/components/ip.component.ts
import { Component, OnInit } from '@angular/core';
import { IpService } from '../services/ip.service';

@Component({
  selector: 'app-ip',
  template: '',
})
export class IpComponent implements OnInit {
  constructor(private ipService: IpService) {}

  ngOnInit() {
    this.ipService.getIpAddresses().subscribe(data => console.log(data));
  }
}

πŸ”— Reference: Angular Services & Dependency Injection


Vue Implementation πŸ”΅

Using Vue Pinia/Vuex for API interactions.

1. Vanilla HTML for UI πŸ“„

(Same as Angular)

2. Vue Store for API Calls πŸ”—

// src/store/ipStore.js
import { defineStore } from 'pinia';
import { ref } from 'vue';

export const useIpStore = defineStore('ipStore', () => {
  const ipAddresses = ref([]);
  
  async function fetchIpAddresses() {
    const res = await fetch('https://67d944ca00348dd3e2aa65f4.mockapi.io/ip-addresses');
    ipAddresses.value = await res.json();
  }

  return { ipAddresses, fetchIpAddresses };
});

3. Vue Component for API Logic πŸŽ›οΈ

// src/components/IpComponent.vue
<script setup>
import { useIpStore } from '../store/ipStore';
const store = useIpStore();

store.fetchIpAddresses();
</script>
<template></template>

πŸ”— Reference: Pinia State Management


React Implementation βš›οΈ

Using React Context API for API calls.

1. Vanilla HTML for UI πŸ“„

(Same as Angular)

2. React Context for API Data Handling πŸ”—

// src/context/IpContext.js
import { createContext, useState, useEffect } from 'react';

export const IpContext = createContext();

export function IpProvider({ children }) {
  const [ipAddresses, setIpAddresses] = useState([]);

  useEffect(() => {
    fetch('https://67d944ca00348dd3e2aa65f4.mockapi.io/ip-addresses')
      .then(res => res.json())
      .then(data => setIpAddresses(data));
  }, []);

  return <IpContext.Provider value={{ ipAddresses }}>{children}</IpContext.Provider>;
}

3. React Component for API Logic πŸŽ›οΈ

// src/components/IpComponent.js
import { useContext } from 'react';
import { IpContext } from '../context/IpContext';

export default function IpComponent() {
  const { ipAddresses } = useContext(IpContext);
  console.log(ipAddresses);
  return null;
}

πŸ”— Reference: React Context API


Conclusion 🎯

By decoupling the presentation layer from Angular, Vue, and React: βœ… Designers and front-end developers can freely work with HTML, CSS, and JavaScript.
βœ… Business logic remains structured within the chosen framework.
βœ… API-driven data binding enables seamless updates without UI constraints.


Key References πŸ“š


This write-up aligns with current best practices for separating concerns in web applications while leveraging APIs. πŸš€

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment