Full Trust European Hosting

BLOG about Full Trust Hosting and Its Technology - Dedicated to European Windows Hosting Customer

AngularJS Hosting Europe - HostForLIFE :: Building an Angular Browser-Based Workflow Simulator (Drag Nodes → Simulate Execution)

clock November 21, 2025 07:43 by author Peter

One of the most helpful aspects for contemporary workplace apps is the creation of a browser-based workflow simulator. Custom workflows are frequently required in industries like manufacturing, aviation, banking, insurance, and IT operations. Before releasing the workflow to the real environment, users want to graphically build steps, connect nodes, establish rules, conduct simulations, and observe how the workflow works.

This article describes how to use Angular to create a Workflow Simulator that is suitable for production. The system facilitates:

The system supports:

  • Drag-and-drop node creation
  • Graph-based workflow builder
  • Branching paths and decision nodes
  • Node configuration panels
  • Execution simulation with event logs
  • Validation of loops, unreachable nodes, and broken paths
  • Pluggable rule engine
  • JSON-based storage and replay
  • Real-time visualisation of execution path

The goal is to build an Angular-based workflow editor that functions like lightweight versions of Camunda Modeler, Node-RED, or n8n, but fully customisable for your product.

Why Build a Workflow Simulator?
Typical enterprise systems contain long-running or multi-step business processes. Before executing workflows in production, developers and business users need a safe sandbox to test logic.

A browser-based simulator allows:

  • Quick iteration
  • Visual understanding of flows
  • Troubleshooting of decision logic
  • Validation before saving workflows
  • Replaying actual data
  • Training and demonstration


Most importantly, it reduces rework and production issues.

High-Level Features Required
A workflow simulator must include:

  • Node palette (Start, Task, Decision, API Call, Script, End).
  • Drag-and-drop canvas.
  • Connectors between nodes.
  • Node configuration (name, rules, conditions, inputs).
  • JSON export/import of the workflow.
  • Execution engine to simulate the workflow step-by-step.
  • Visual highlight of execution path.
  • Validation engine.
  • Undo/redo support.
  • Event logs and breakpoints.

This article focuses on the Angular implementation, core architecture, and execution simulation.

High-Level Architecture
The system is divided into:

  • Canvas Module
  • Nodes Module
  • Connection Engine
  • Workflow Engine (simulation)
  • Persistence Module
  • Validation Module
  • UI Components (palette, config panel)
Designing the Workflow Data Model
A workflow is a directed graph. Each node represents a step, and each edge represents the flow.

Node Structure
export interface WorkflowNode {
  id: string;
  type: 'start' | 'task' | 'decision' | 'api' | 'script' | 'end';
  name: string;
  position: { x: number; y: number };
  config?: any;
}
Edge Structure
export interface WorkflowEdge {
  id: string;
  from: string;
  to: string;
  condition?: string; // expression or rule
}
Workflow Definition
export interface WorkflowDefinition {
  nodes: WorkflowNode[];
  edges: WorkflowEdge[];
}

Building the Canvas in Angular

You will use these libraries/tools:
  • Angular CDK DragDrop Module
  • HTML canvas or SVG for rendering
  • RxJS for state management
  • A lightweight graph calculation library (optional)
Basic Canvas Component
@Component({
  selector: 'app-workflow-canvas',
  templateUrl: './workflow-canvas.component.html',
  styleUrls: ['./workflow-canvas.component.css']
})
export class WorkflowCanvasComponent {
  @Input() workflow!: WorkflowDefinition;

  onNodeDrag(event: CdkDragMove, node: WorkflowNode) {
    node.position.x = event.pointerPosition.x;
    node.position.y = event.pointerPosition.y;
  }
}

Canvas Template

<div class="canvas-area">
  <div *ngFor="let node of workflow.nodes"
       class="node"
       cdkDrag
       [style.left.px]="node.position.x"
       [style.top.px]="node.position.y">
       {{ node.name }}
  </div>

  <svg class="edge-layer">
    <ng-container *ngFor="let edge of workflow.edges">
      <line
        [attr.x1]="getNode(edge.from).position.x + 50"
        [attr.y1]="getNode(edge.from).position.y + 20"
        [attr.x2]="getNode(edge.to).position.x"
        [attr.y2]="getNode(edge.to).position.y"
        stroke="black"
        stroke-width="2" />
    </ng-container>
  </svg>
</div>

Implementing Drag-and-Drop Node Palette

A simple palette:
<div class="palette">
  <button (click)="addNode('task')">Add Task</button>
  <button (click)="addNode('decision')">Add Decision</button>
  <button (click)="addNode('api')">Add API Call</button>
</div>
Add Node Logic
addNode(type: string) {
  const newNode: WorkflowNode = {
    id: crypto.randomUUID(),
    type,
    name: `${type} node`,
    position: { x: 100, y: 100 }
  };

  this.workflow.nodes.push(newNode);
}

Adding Connectors Between Nodes

Common approach:
  • Click first node.
  • Click second node.
  • Create edge.
Add Edge Logic
addEdge(fromId: string, toId: string) {
  this.workflow.edges.push({
    id: crypto.randomUUID(),
    from: fromId,
    to: toId
  });
}

Adding Node Configuration Panel

This allows editing:
  • Name
  • Inputs
  • Conditions
  • Output fields
  • API parameters
  • Decision expressions
Sample Configuration Panel
<div class="config-panel" *ngIf="selectedNode">
  <h3>Node Configuration</h3>
  <label>Name:
    <input [(ngModel)]="selectedNode.name" />
  </label>

  <label *ngIf="selectedNode.type === 'decision'">
    Condition:
    <input [(ngModel)]="selectedNode.config.condition" />
  </label>
</div>

The Workflow Execution Engine

The Workflow Engine runs the workflow.
This includes:
  • Loading workflow JSON
  • Finding the start node
  • Executing each node
  • Evaluating rules
  • Logging events
  • Highlighting visited nodes
Engine Structure
export class WorkflowEngine {
  constructor(private workflow: WorkflowDefinition) {}

  private logs: string[] = [];

  execute() {
    let currentNode = this.findStartNode();

    while (currentNode && currentNode.type !== 'end') {
      this.logs.push(`Executing: ${currentNode.name}`);
      currentNode = this.getNextNode(currentNode);
    }

    this.logs.push('Reached end node');
    return this.logs;
  }
}


Rule Evaluation for Decision Nodes
Rules may be:
  • JavaScript expressions
  • JSON-based rule definitions
  • Condition strings
Example Rule Evaluation
evaluateCondition(condition: string, context: any): boolean {
  const fn = new Function("context", `return ${condition}`);
  return fn(context);
}

For large enterprise systems, use a safe rule engine instead of dynamic functions.

Simulating Execution Step-by-Step

Support:
  • Automatic play
  • Manual step-by-step
  • Breakpoints
Step Mode Example
step() {
  if (!this.currentNode) {
    this.currentNode = this.findStartNode();
    return this.currentNode;
  }

  this.currentNode = this.getNextNode(this.currentNode);
  return this.currentNode;
}


Visualising Execution Path
When the simulator runs:
  • Highlight the active node
  • Highlight the traversed edges
  • Dim inactive nodes
Canvas Highlighting Example
.node.active {
  border: 2px solid blue;
}

.edge.active {
  stroke: blue;
}

You will toggle CSS classes based on execution logs.

Validations Before Simulation
Essential validations:
  • Workflow must contain exactly one start node.
  • All nodes must be reachable from start.
  • No cycles unless allowed.
  • Decision nodes must contain valid conditions.
  • All edges must reference valid node IDs.
Example Validation Function
validateWorkflow(workflow: WorkflowDefinition): string[] {
  const errors: string[] = [];

  const startNodes = workflow.nodes.filter(n => n.type === 'start');
  if (startNodes.length !== 1) {
    errors.push('Workflow must contain exactly one start node.');
  }

  // Additional validations…

  return errors;
}

JSON Export and Import
The workflow editor must support saving and loading.

Export
downloadJSON() {
  const json = JSON.stringify(this.workflow);
  // download logic
}
Import
uploadWorkflow(json: string) {
  this.workflow = JSON.parse(json);
}

Undo / Redo Support

Use an RxJS BehaviorSubject to push state snapshots.

Example
history: WorkflowDefinition[] = [];
historyIndex = -1;

pushState() {
  this.history.push(JSON.parse(JSON.stringify(this.workflow)));
  this.historyIndex++;
}

Undo
undo() {
  if (this.historyIndex > 0) {
    this.historyIndex--;
    this.workflow = JSON.parse(JSON.stringify(this.history[this.historyIndex]));
  }
}

Real-World Challenges and Best Practices

Performance drops when rendering more than 200 nodes.
Use canvas or WebGL for large workflows.

Users need zooming and panning.
Implement with CSS transforms.

Complex connectors require bezier curves.
Use SVG path elements.

Decision rules get messy.
Integrate a rules engine (Nools, JSON-rules-engine).

Autosaving is essential.
Persist state in localStorage every few seconds.

Multi-user collaboration.
Use WebSockets and operational transforms.

Prevent invalid node drops.
Add guards and context checks.

Production-Level Recommendations
Use a state management library (NgRx or Akita) for storing workflow state.

Use RxJS Subjects for canvas events.

Debounce drag events to reduce change detection load.

Generate node IDs using crypto APIs for uniqueness.

Allow theming and custom node templates.

Include snap-to-grid behaviour for cleaner diagrams.

Create extension hooks for future custom nodes.

Conclusion

A browser-based workflow simulator is a powerful and reusable tool for any enterprise Angular application. By combining a graph-based canvas, configurable nodes, a robust execution engine, and a validation system, you can build a complete workflow modelling and testing system inside the browser. What makes this solution truly valuable is its flexibility. It doesn’t depend on any external engine and can be adapted for HR approvals, manufacturing processes, IT automation, financial rules, document processing, and more.


AngularJS Hosting Europe - HostForLIFE :: Using Angular +.NET to Create a Custom Rich Text Editor with Auto-Save and Mentions (@user)

clock November 19, 2025 08:11 by author Peter

Advanced text-editing features, such as inline formatting, auto-save drafts, mentions, and collaboration-ready structures, are becoming more and more necessary for modern workplace applications. Building your own lightweight Angular-based rich text editor gives you complete control, extensibility, and minimal dependency risk, whereas many teams rely on bulky third-party WYSIWYG editors.

DATABASE SCRIPT (SQL Server)
1. Users Table

CREATE TABLE Users (
    UserId INT IDENTITY PRIMARY KEY,
    DisplayName VARCHAR(100),
    Email VARCHAR(150)
);

2. DocumentDrafts Table

CREATE TABLE DocumentDrafts (
    DraftId INT IDENTITY PRIMARY KEY,
    DocumentId INT NOT NULL,
    Content NVARCHAR(MAX),
    LastSaved DATETIME DEFAULT GETDATE()
);

.NET BACKEND (ASP.NET Core 8 API)
1. Model

public class DocumentDraft
{
    public int DocumentId { get; set; }
    public string Content { get; set; }
}

2. Controller: EditorController.cs

[ApiController]
[Route("api/[controller]")]
public class EditorController : ControllerBase
{
    private readonly IConfiguration _config;

    public EditorController(IConfiguration config)
    {
        _config = config;
    }

    [HttpPost("saveDraft")]
    public async Task<IActionResult> SaveDraft([FromBody] DocumentDraft draft)
    {
        using SqlConnection con = new(_config.GetConnectionString("Default"));
        using SqlCommand cmd = new("IF EXISTS (SELECT 1 FROM DocumentDrafts WHERE DocumentId=@Id)
                                         UPDATE DocumentDrafts SET Content=@C, LastSaved=GETDATE() WHERE DocumentId=@Id
                                   ELSE
                                         INSERT INTO DocumentDrafts(DocumentId, Content) VALUES(@Id, @C)", con);

        cmd.Parameters.AddWithValue("@Id", draft.DocumentId);
        cmd.Parameters.AddWithValue("@C", draft.Content);

        con.Open();
        await cmd.ExecuteNonQueryAsync();

        return Ok(new { message = "Draft saved" });
    }

    [HttpGet("getDraft/{documentId}")]
    public async Task<IActionResult> GetDraft(int documentId)
    {
        using SqlConnection con = new(_config.GetConnectionString("Default"));
        using SqlCommand cmd = new("SELECT Content FROM DocumentDrafts WHERE DocumentId=@Id", con);

        cmd.Parameters.AddWithValue("@Id", documentId);

        con.Open();
        string? content = (string?)await cmd.ExecuteScalarAsync();

        return Ok(new { content });
    }
}

3. UsersController.cs for mentions

[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
    private readonly IConfiguration _config;

    public UsersController(IConfiguration config)
    {
        _config = config;
    }

    [HttpGet("search")]
    public async Task<IActionResult> Search([FromQuery] string q)
    {
        using SqlConnection con = new(_config.GetConnectionString("Default"));
        using SqlCommand cmd = new("SELECT TOP 10 UserId, DisplayName FROM Users WHERE DisplayName LIKE @Q + '%'", con);

        cmd.Parameters.AddWithValue("@Q", q);

        con.Open();
        List<object> users = new();

        using SqlDataReader dr = await cmd.ExecuteReaderAsync();
        while (await dr.ReadAsync())
        {
            users.Add(new
            {
                UserId = dr.GetInt32(0),
                DisplayName = dr.GetString(1)
            });
        }

        return Ok(users);
    }
}

ANGULAR IMPLEMENTATION (FULL MODULE)
1. Module + Routing

editor.module.ts
@NgModule({
  declarations: [
    EditorComponent,
    MentionDropdownComponent
  ],
  imports: [
    CommonModule,
    FormsModule,
    RouterModule.forChild([
      { path: '', component: EditorComponent }
    ])
  ]
})
export class EditorModule {}


2. Editor Component UI
editor.component.html

<div class="toolbar">
  <button (click)="format('bold')">B</button>
  <button (click)="format('italic')">I</button>
  <button (click)="format('underline')">U</button>
</div>

<div class="editor-container">
  <div class="editor"
       contenteditable="true"
       (keyup)="onKeyUp($event)"
       (click)="closeMention()"
       #editor>
  </div>

  <app-mention-dropdown
      *ngIf="showMention"
      [items]="mentionResults"
      (select)="insertMention($event)">
  </app-mention-dropdown>
</div>


3. Editor Component TS
editor.component.ts

export class EditorComponent implements OnInit, OnDestroy {
  @ViewChild('editor') editor!: ElementRef;

  autoSaveInterval: any;
  showMention = false;
  mentionResults: any[] = [];
  mentionText = "";
  cursorPos = 0;

  constructor(private api: EditorService, private users: UsersService) {}

  ngOnInit(): void {
    this.loadDraft();
    this.startAutoSave();
  }

  format(cmd: string) {
    document.execCommand(cmd, false, '');
  }

  onKeyUp(event: KeyboardEvent) {
    const value = this.getContent();
    const char = event.key;

    if (char === '@') {
      this.showMention = true;
      this.mentionText = "";
    }

    if (this.showMention && char !== '@') {
      this.mentionText += char;
      this.searchUsers();
    }
  }

  searchUsers() {
    this.users.search(this.mentionText).subscribe(res => {
      this.mentionResults = res;
    });
  }

  insertMention(user: any) {
    document.execCommand("insertHTML", false, `<span class='mention'>@${user.displayName}</span>&nbsp;`);
    this.showMention = false;
  }

  getContent() {
    return this.editor.nativeElement.innerHTML;
  }

  loadDraft() {
    this.api.getDraft(1).subscribe(r => {
      if (r.content) this.editor.nativeElement.innerHTML = r.content;
    });
  }

  startAutoSave() {
    this.autoSaveInterval = setInterval(() => {
      const content = this.getContent();
      this.api.saveDraft({ documentId: 1, content }).subscribe();
    }, 3000);
  }

  ngOnDestroy() {
    clearInterval(this.autoSaveInterval);
  }

  closeMention() {
    this.showMention = false;
  }
}


4. Mention Dropdown Component
mention-dropdown.component.html

<div class="mention-box">
  <div *ngFor="let u of items" (click)="onSelect(u)">
      {{u.displayName}}
  </div>
</div>


mention-dropdown.component.ts
@Component({
  selector: 'app-mention-dropdown',
  templateUrl: './mention-dropdown.component.html'
})
export class MentionDropdownComponent {
  @Input() items: any[] = [];
  @Output() select = new EventEmitter<any>();

  onSelect(u: any) {
    this.select.emit(u);
  }
}

5. Services
editor.service.ts

@Injectable({ providedIn: 'root' })
export class EditorService {

  constructor(private http: HttpClient) {}

  saveDraft(model: any) {
    return this.http.post('/api/editor/saveDraft', model);
  }

  getDraft(id: number) {
    return this.http.get<any>(`/api/editor/getDraft/${id}`);
  }
}
users.service.ts

@Injectable({ providedIn: 'root' })
export class UsersService {
  constructor(private http: HttpClient) {}

  search(q: string) {
    return this.http.get<any[]>(`/api/users/search?q=${q}`);
  }
}
UI Styling (CSS)
editor.component.css
.toolbar button {
  margin-right: 6px;
  padding: 4px;
}

.editor {
  min-height: 300px;
  border: 1px solid #ccc;
  padding: 12px;
  border-radius: 5px;
}

.mention {
  background: #e3f2fd;
  color: #0277bd;
  padding: 2px 4px;
  border-radius: 4px;
}

.mention-box {
  position: absolute;
  background: white;
  border: 1px solid #ccc;
  width: 200px;
  z-index: 999;
  border-radius: 4px;
}

.mention-box div {
  padding: 6px;
  cursor: pointer;
}

.mention-box div:hover {
  background: #f1f1f1;
}



AngularJS Hosting Europe - HostForLIFE :: Using Web Workers to Optimize Angular Performance for Complex Calculations

clock November 13, 2025 09:09 by author Peter

Performance and responsiveness are important aspects of the user experience in contemporary single-page applications (SPAs). Although Angular is a strong framework for creating dynamic apps, the user interface (UI) may become sluggish or unresponsive when your application must manage sophisticated mathematical operations, data processing, or significant computations. This occurs because Angular's programming language, JavaScript, operates in a single thread, which means that data processing, user interactions, and UI updates all vie for the same execution line.


 In order to address this issue, browsers offer a robust feature called Web Workers, which enables you to execute background operations concurrently without interfering with the main thread.

In this article, we’ll explore how to use Web Workers in Angular, understand when to use them, and walk through a step-by-step implementation for improving app performance with real-world examples.

What Are Web Workers?
Web Workers are background scripts that run independently from the main JavaScript thread.
They allow you to perform CPU-intensive tasks — like image processing, data encryption, or large JSON transformations — without freezing your UI.

Key characteristics

  • Run in a separate thread (parallel to the main UI).
  • Communicate via message passing (using postMessage() and onmessage).
  • Have no direct access to DOM or global variables.
  • Can perform complex logic or data manipulation safely.

Example scenario
Imagine processing a large dataset of 100,000 records in an Angular app. Doing this directly in a component method can cause UI lag.
With a Web Worker, the processing happens in the background, and once completed, the result is sent back — keeping your UI smooth and responsive.

When Should You Use Web Workers?
Use Web Workers when:
You’re performing CPU-heavy or long-running tasks:

  • Mathematical computations
  • Image or video encoding
  • Parsing large JSON or XML files
  • Cryptographic or hashing operations

Your Angular app experiences frame drops or freezing during data operations.
You want to keep animations and interactions smooth while processing data in the background.

Avoid Web Workers when:

  • The task is lightweight or runs instantly.
  • You need direct DOM access.
  • The overhead of message passing outweighs benefits.

Step-by-Step Implementation in Angular
Let’s implement a practical example to understand Web Workers in Angular.

We’ll create a Prime Number Calculator — a CPU-heavy task that can easily freeze the UI if executed in the main thread.

Step 1: Create a New Angular Project
If you don’t already have one:
ng new web-worker-demo
cd web-worker-demo


Step 2: Generate a Web Worker
Angular CLI provides built-in support for workers:
ng generate web-worker app

You’ll be asked:
? Would you like to add Angular CLI support for Web Workers? Yes

Once done, Angular automatically:
Updates tsconfig.json with "webWorker": true

Creates a new file: src/app/app.worker.ts

Step 3: Write Logic in the Worker File
Open src/app/app.worker.ts and add the heavy computation logic.
/// <reference lib="webworker" />

// Function to find prime numbers up to a given limitfunction generatePrimes(limit: number): number[] {
  const primes: number[] = [];
  for (let i = 2; i <= limit; i++) {
    let isPrime = true;
    for (let j = 2; j * j <= i; j++) {
      if (i % j === 0) {
        isPrime = false;
        break;
      }
    }
    if (isPrime) primes.push(i);
  }
  return primes;
}

// Listen for messages from main threadaddEventListener('message', ({ data }) => {
  const primes = generatePrimes(data);
  postMessage(primes);
});

This worker listens for a message containing a number limit, computes prime numbers up to that limit, and sends them back to the main Angular thread.

Step 4: Modify the Component

Open src/app/app.component.ts:
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
    <div style="text-align:center; padding:20px;">
      <h2>Angular Web Worker Demo</h2>
      <input type="number" [(ngModel)]="limit" placeholder="Enter number" />
      <button (click)="calculate()">Generate Primes</button>
      <p *ngIf="loading">Calculating, please wait...</p>
      <div *ngIf="!loading && result.length">
        <h3>Prime Numbers:</h3>
        <p>{{ result.join(', ') }}</p>
      </div>
    </div>
  `,
})
export class AppComponent implements OnInit {
  limit = 100000;
  result: number[] = [];
  loading = false;
  worker!: Worker;

  ngOnInit(): void {
    if (typeof Worker !== 'undefined') {
      this.worker = new Worker(new URL('./app.worker', import.meta.url));
      this.worker.onmessage = ({ data }) => {
        this.result = data;
        this.loading = false;
      };
    } else {
      alert('Web Workers are not supported in this browser!');
    }
  }

  calculate() {
    this.loading = true;
    this.worker.postMessage(this.limit);
  }
}

Step 5: Enable FormsModule for ngModel
In app.module.ts, import the FormsModule:
import { FormsModule } from '@angular/forms';

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, FormsModule],
  bootstrap: [AppComponent],
})
export class AppModule {}


Step 6: Run the Application
Run the Angular app:
ng serve

Open the browser at http://localhost:4200 and enter a large number like 100000.
Without Web Workers, the UI would freeze; now it remains smooth while computation happens in the background.

How It Works?

  • When the user clicks Generate Primes, the component sends a message to the Web Worker using postMessage().
  • The worker executes generatePrimes() in a separate thread.
  • Once computation finishes, the worker sends results back using postMessage().
  • The Angular component receives the result via onmessage and updates the UI.
Error Handling in Workers
You can also handle runtime errors gracefully.
this.worker.onerror = (error) => {
  console.error('Worker error:', error);
  this.loading = false;
};

Always include fallback logic if a browser doesn’t support Web Workers.

Terminating a Worker
If a user cancels an operation midway, terminate the worker:
if (this.worker) {
  this.worker.terminate();
}

This ensures memory is freed and no unnecessary computation continues in the background.

Advanced Example: JSON Data Processing
Suppose your Angular app downloads a 50MB JSON file and you want to filter and aggregate data efficiently.
Worker (data.worker.ts)

addEventListener('message', ({ data }) => {
  const result = data.filter((x: any) => x.isActive);
  postMessage(result.length);
});

Component
this.worker.postMessage(largeJsonArray);
this.worker.onmessage = ({ data }) => {
  console.log('Active records count:', data);
};

The computation runs in the worker thread, keeping your UI smooth.

Combining Web Workers with RxJS
You can wrap the Web Worker communication in an RxJS Observable for a cleaner and reactive design.
calculatePrimes(limit: number): Observable<number[]> {
  return new Observable((observer) => {
    const worker = new Worker(new URL('./app.worker', import.meta.url));
    worker.onmessage = ({ data }) => {
      observer.next(data);
      observer.complete();
      worker.terminate();
    };
    worker.onerror = (err) => observer.error(err);
    worker.postMessage(limit);
  });
}

This allows seamless integration with Angular’s reactive programming pattern.

Best Practices for Using Web Workers in Angular
Use Workers for CPU-Intensive Tasks Only
Avoid creating unnecessary workers for small operations.

Limit the Number of Workers
Each worker consumes memory; don’t overload the browser.

Terminate Workers When Not Needed
Prevent memory leaks by calling worker.terminate().

Serialize Data Efficiently
Minimize payload size when using postMessage().

Use SharedArrayBuffer (if needed)
For high-performance use cases, shared memory can reduce data transfer overhead.

Profile Performance
Use Chrome DevTools → Performance tab to measure improvement.

Integration with ASP.NET Core Backend
While Web Workers run in the browser, you can integrate them with your ASP.NET Core backend to optimize client-server performance.
For example:

The worker can pre-process data (filter, aggregate) before sending it to the API.

The API only receives minimal, structured data.

This combination reduces network payloads and API processing time — improving overall system efficiency.

Conclusion

Web Workers are one of the most underutilized features in frontend development. For Angular applications dealing with heavy computations or large data processing, using Web Workers can dramatically enhance performance and user experience. They ensure the main UI thread remains responsive, users experience smooth interactions, and complex tasks run efficiently in parallel.

By implementing Web Workers effectively — and combining them with Angular’s reactive ecosystem — developers can build high-performance, scalable web apps that deliver a desktop-like experience, even for complex workloads.


AngularJS Hosting Europe - HostForLIFE :: Using Angular 19 with ASP.NET Core 9 to Create a Scalable Web Application

clock November 12, 2025 07:12 by author Peter

The aim of every developer in contemporary web development is to create an application that is high-performing, scalable, and maintained.
A robust, modular, and cloud-ready full-stack solution may be achieved by combining Angular 19 for the frontend and ASP.NET Core 9 for the backend.

Developers looking for a realistic, hands-on approach covering everything from architecture setup to production deployment should read this article.

Why ASP.NET Core 9 + Angular 19?

FeatureAngular 19 (Frontend)ASP.NET Core 9 (Backend)
Language TypeScript C#
Rendering SSR + CSR + Hydration API-first
Build System Standalone components, Signals, ESBuild Minimal APIs, gRPC, Native AOT
Performance Improved reactivity model Optimized for microservices
Dev Tools Angular CLI 19, Vite .NET CLI, EF Core 9
Ideal Use SPAs, PWAs REST APIs, Web APIs, Services

Angular handles rich UI and real-time interaction, while ASP.NET Core delivers high-speed APIs and scalable backend logic.

Step 1: Architecture Design
A scalable architecture clearly delineates roles.

Step 2: Setting up the Backend (ASP.NET Core 9)
Create the API Project
dotnet new webapi -n ScalableApp.Api
cd ScalableApp.Api


Example: Model Class
public class Product
{
    public int Id { get; set; }
    public string Name { get; set; } = string.Empty;
    public decimal Price { get; set; }
}


Example: Repository Pattern
public interface IProductRepository
{
    Task<IEnumerable<Product>> GetAllAsync();
    Task<Product?> GetByIdAsync(int id);
    Task AddAsync(Product product);
}

public class ProductRepository : IProductRepository
{
    private readonly AppDbContext _context;
    public ProductRepository(AppDbContext context) => _context = context;

    public async Task<IEnumerable<Product>> GetAllAsync() => await _context.Products.ToListAsync();
    public async Task<Product?> GetByIdAsync(int id) => await _context.Products.FindAsync(id);
    public async Task AddAsync(Product product)
    {
        _context.Products.Add(product);
        await _context.SaveChangesAsync();
    }
}


Example: Controller
[ApiController]
[Route("api/[controller]")]
public class ProductController : ControllerBase
{
    private readonly IProductRepository _repository;
    public ProductController(IProductRepository repository) => _repository = repository;

    [HttpGet]
    public async Task<IActionResult> GetAll() => Ok(await _repository.GetAllAsync());
}


Step 3: Connect to SQL Server (EF Core 9)
Install EF Core
dotnet add package Microsoft.EntityFrameworkCore.SqlServer
dotnet add package Microsoft.EntityFrameworkCore.Tools

Setup DbContext

public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options)
        : base(options) { }

    public DbSet<Product> Products => Set<Product>();
}

Register in Program.cs
builder.Services.AddDbContext<AppDbContext>(opt =>
    opt.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
builder.Services.AddScoped<IProductRepository, ProductRepository>();


Example appsettings.json
{"ConnectionStrings": {
    "DefaultConnection": "Server=localhost;Database=ScalableAppDB;Trusted_Connection=True;"}}


Step 4: Building the Frontend (Angular 19)
Create Angular App

ng new scalable-app --standalone
cd scalable-app
ng serve

Install Required Packages
npm install @angular/material @angular/forms @angular/common rxjs

Create a Product Service
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

export interface Product {
  id: number;
  name: string;
  price: number;
}

@Injectable({ providedIn: 'root' })
export class ProductService {
  private apiUrl = 'https://localhost:5001/api/product';

  constructor(private http: HttpClient) {}

  getAll(): Observable<Product[]> {
    return this.http.get<Product[]>(this.apiUrl);
  }
}


Display Products in Component
import { Component, OnInit, signal } from '@angular/core';
import { ProductService, Product } from '../services/product.service';

@Component({
  selector: 'app-product-list',
  standalone: true,
  template: `
    <h2>Product List</h2>
    <ul>
      <li *ngFor="let p of products()">
        {{ p.name }} - {{ p.price | currency }}
      </li>
    </ul>
  `
})
export class ProductListComponent implements OnInit {
  products = signal<Product[]>([]);

  constructor(private service: ProductService) {}

  ngOnInit() {
    this.service.getAll().subscribe(res => this.products.set(res));
  }
}


Step 5: Add Authentication (JWT + Angular Guard)
Backend (ASP.NET Core)

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = "https://yourapi.com",
            ValidAudience = "https://yourapp.com",
            IssuerSigningKey = new SymmetricSecurityKey(
                Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]))
        };
    });

Frontend (Angular 19 Guard)
import { CanActivateFn } from '@angular/router';
export const authGuard: CanActivateFn = () => {
  const token = localStorage.getItem('token');
  return !!token;
};

Step 6: Deployment Strategy
Angular Build for Production

ng build --configuration production

The build output will be in /dist/scalable-app.

ASP.NET Core Publish

dotnet publish -c Release -o ./publish

Host Both Together
Place Angular’s built files inside ASP.NET Core’s wwwroot folder.
Modify Program.cs:
app.UseDefaultFiles();
app.UseStaticFiles();
app.MapFallbackToFile("index.html");

Step 7: Best Practices for Scalability

AreaBest Practice
API Use async methods and pagination
Database Use stored procedures for heavy queries
Caching Add MemoryCache / Redis for repeated API calls
Logging Centralize logs with Serilog / Application Insights
Security Use HTTPS, JWT, and CORS configuration
Frontend Lazy load routes and use Angular Signals
DevOps Use CI/CD pipelines (GitHub Actions / Azure DevOps)

Step 8: CI/CD Integration
Example GitHub Actions pipeline for .NET + Angular:
name: Build and Deploy
on:push:
    branches: [ main ]

jobs:build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Setup .NET
        uses: actions/setup-dotnet@v4
        with:
          dotnet-version: '9.0.x'
      - name: Build .NET API
        run: dotnet publish ./ScalableApp.Api -c Release -o ./publish

      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          node-version: '20'
      - name: Build Angular
        run: |
          cd scalable-app
          npm ci
          npm run build

Full-Stack Flow Diagram
[ Angular 19 UI ]
            |
(HTTP calls via HttpClient)
            ↓
   [ ASP.NET Core 9 API ]
            |
   [ Business Logic Layer ]
            |
   [ EF Core Repository ]
            |
   [ SQL Server Database ]


Conclusion
By combining Angular 19 and ASP.NET Core 9, you can build a robust, modular, and enterprise-grade web application that scales effortlessly.

Key takeaways:
Use layered architecture for clean separation of concerns.
Integrate EF Core 9 for fast database operations.
Apply JWT authentication for secure communication.
Deploy via CI/CD pipelines for efficiency and reliability.
With this setup, your web app is ready for both enterprise growth and modern cloud environments.



AngularJS Hosting Europe - HostForLIFE :: Using Angular Standalone Components and Signal APIs to Create High-Performance User Interfaces

clock November 4, 2025 06:45 by author Peter

Angular has made significant progress in recent years to improve runtime performance and simplify app structure. Developers can now create apps that load more quickly, operate more smoothly, and require less maintenance thanks to Angular Standalone Components and the new Signal API. This post will explain these capabilities, their significance, and how to combine them to create cutting-edge, lightning-fast Angular applications.

1. Standalone Components: What Are They?
In the past, each Angular component required to be a part of a NgModule.
However, you can create Standalone Components starting with Angular 14 and now fully stable with Angular 17+, so they don't need to be specified inside a module.

Example: Creating a Standalone Component
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';

@Component({
  selector: 'app-dashboard',
  standalone: true,
  imports: [CommonModule],
  template: `<h2>Welcome to Dashboard!</h2>`
})
export class DashboardComponent {}


No @NgModule needed!
You can directly use this component in routing or even bootstrap it in main.ts.

2. Bootstrapping with Standalone Components
With standalone components, even your AppModule becomes optional.
Example:
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';

bootstrapApplication(AppComponent)
  .catch(err => console.error(err));


That’s it no AppModule required!
This reduces overhead and speeds up the app’s initial load time.

3. Angular Signal API: The Game Changer

The Signal API, introduced in Angular 16+, is a powerful new way to manage reactive state without complex libraries like RxJS or NgRx.

Signals are reactive variables that automatically update the UI whenever their value changes.

Example: Simple Counter Using Signal
import { Component, signal } from '@angular/core';

@Component({
  selector: 'app-counter',
  standalone: true,
  template: `
    <h2>Count: {{ count() }}</h2>
    <button (click)="increment()">Increment</button>
  `
})
export class CounterComponent {
  count = signal(0);

  increment() {
    this.count.update(c => c + 1);
  }
}


No BehaviorSubject, no subscriptions just simple, reactive code.

4. How Signals Improve Performance
With traditional change detection, Angular re-renders components unnecessarily.
Signals fix this by using fine-grained reactivity — only updating parts of the UI that actually change.

This means:

  • Less re-rendering
  • Better performance
  • Cleaner codebase

5. Combining Standalone Components and Signals
Together, Standalone Components and Signals make Angular apps simpler and more efficient.

Here’s an example of how both can be used in a real-world scenario like a Product Dashboard.
Example: Product Dashboard with Reactive State
import { Component, signal } from '@angular/core';
import { CommonModule } from '@angular/common';

@Component({
  selector: 'app-product-dashboard',
  standalone: true,
  imports: [CommonModule],
  template: `
    <h1>Product Dashboard</h1>
    <input type="text" placeholder="Search product..." (input)="search($event)">
    <ul>
      <li *ngFor="let p of filteredProducts()">{{ p }}</li>
    </ul>
  `
})
export class ProductDashboardComponent {
  products = signal(['TV', 'Fridge', 'Laptop', 'Fan', 'Microwave']);
  filteredProducts = signal(this.products());

  search(event: any) {
    const keyword = event.target.value.toLowerCase();
    this.filteredProducts.set(
      this.products().filter(p => p.toLowerCase().includes(keyword))
    );
  }
}


Here:

  • Signals manage product lists.
  • Standalone Component keeps the code modular and fast.
  • The UI updates instantly without manual subscriptions.

6. Flowchart: How It Works
Below is a simple visual flow for your blog (you can design this using Canva or draw.io):

User Action (e.g., Click or Input)
          ↓
 Signal Updates (state change)
          ↓
 Angular detects signal change
          ↓
 Component Re-renders (only affected part)
          ↓
 UI Updates Instantly

This shows how Signals streamline UI updates with minimal re-rendering.

7. Responsive UI Example with PrimeNG

Now let’s combine Angular + PrimeNG to make a clean, responsive dashboard.
Example UI Structure

-------------------------------------
| Header: App Title + Menu Button   |
-------------------------------------
| Sidebar |     Main Dashboard      |
|         |  - Charts               |
|         |  - Stats Cards          |
|         |  - Product List         |
-------------------------------------

PrimeNG Components Used:
p-card for summary boxes
p-table for data grids
p-chart for performance visualization
p-sidebar for navigation

Example Snippet
<p-sidebar [(visible)]="menuVisible">
  <h3>Menu</h3>
  <p>Dashboard</p>
  <p>Reports</p>
</p-sidebar>

<p-card header="Total Sales">
  <h2>{{ totalSales() | currency }}</h2>
</p-card>

<p-chart type="bar" [data]="chartData()"></p-chart>

Your app becomes lighter, more modular, and boots up more quickly as a result. 
This gives a smooth, mobile-friendly dashboard that responds instantly due to Signals.

8. Performance Comparison

FeatureBefore (RxJS/Modules)Now (Signals/Standalone)

App Bootstrap

Slower

Faster

State Management

Complex

Simple

Change Detection

Broad

Fine-grained

Code Size

Larger

Smaller

Learning Curve

Steep

Easier

9. Real-World Benefits

  • Faster App Loading
  • Simplified Codebase
  • No Extra Libraries
  • Better Reusability
  • Improved UI Responsiveness

10. Conclusion
Angular is now quicker, lighter, and easier for developers to use thanks to Standalone Components and Signals. These capabilities allow you create contemporary, high-performance user interfaces with clear, reactive logic while streamlining structure and improving speed. Now is the ideal moment to update your Angular projects if you haven't already.



About HostForLIFE.eu

HostForLIFE.eu is European Windows Hosting Provider which focuses on Windows Platform only. We deliver on-demand hosting solutions including Shared hosting, Reseller Hosting, Cloud Hosting, Dedicated Servers, and IT as a Service for companies of all sizes.

We have offered the latest Windows 2016 Hosting, ASP.NET Core 2.2.1 Hosting, ASP.NET MVC 6 Hosting and SQL 2017 Hosting.


Tag cloud

Sign in