Skip to main content

Command Palette

Search for a command to run...

Why Does Your Angular Component State Reset When You Move It? A Deep Dive into CDK Portals

Understanding the difference between recreating views and moving DOM elements

Published
4 min read
Why Does Your Angular Component State Reset When You Move It? A Deep Dive into CDK Portals
R

Development is My Passion | Architecting is My Impact | 10 Library author | 100 + Technical Articles | 3+ Tech Talks

With over a decade of experience in front-end development, I specialize in crafting pixel-perfect, user-centric websites and applications. My extensive expertise covers a wide range of technologies, including React, Redux, Angular, Ngrx, Vue.js, React Native, JavaScript (ES6–12), TypeScript, OOJS, HTML, CSS, Microservices, Unit Testing (Jasmine, Karma, Jest), Playwright, IndexedDB, Bootstrap, Tailwind, web security, accessibility, and performance optimization.

I am adept at implementing highly interactive, optimized, and scalable web applications, with a strong emphasis on efficient algorithms, object-oriented programming, and design patterns. My proficiency in creating responsive designs has not only enhanced user experiences but also significantly reduced mobile development costs.

Throughout my career, I've made impactful contributions to cloud-based applications across diverse sectors, including eCommerce, telecommunications, delivery services, food, energy automation, and finance. My work in these areas has consistently driven success and innovation.

I am dedicated to continuous learning and staying at the forefront of web development trends and technologies. My motivation lies in leading and contributing to the development of next-generation products, ensuring they are fast, optimized, robust, cloud-native, fault-tolerant, and scalable.

In my current role, I have been instrumental in the success of several high-impact projects, including the redesign of a major energy automation platform. This initiative led to a 24% increase in revenue, a 47% boost in performance, and a 32% growth in customer acquisition. With BE driven page, reduce 13% development effort

In addition to building scalable, high-performance products, I actively leverage AI-driven tools (ChatGPT, GitHub Copilot, AI-assisted prototyping) to accelerate development, boost team productivity, and bring user-centric ideas to life faster.

I am excited to further develop my leadership skills and contribute to organizations that are looking to achieve ambitious goals through cutting-edge front-end development.

If you're seeking a leader and contributor who can drive the creation of modern, high-performing web applications.

Let's get in touch.

Have you ever moved a component from one part of your Angular layout to another, only to watch all its state disappear? The timer resets, the form clears, the toggle switches back—everything vanishes. Frustrating, right?

This isn't a bug. It's how Angular handles component rendering. But here's the thing: most developers don't realize there are multiple ways to move components in Angular, and they behave very differently. Some recreate your component from scratch. Others actually move the live instance, preserving all state.

In this article, we'll explore three approaches to moving components across your layout: ngTemplateOutlet, CDK Template Portal, and CDK DOM Portal. By the end, you'll understand exactly when Angular recreates your views and how to preserve component state when moving elements across your application.

Let's dive into a real-world scenario and see what's actually happening under the hood.


The Problem: Moving Components Kills State

Imagine you're building an admin dashboard with a promotional banner. This banner has interactive elements: a heart button users can click and a live timer counting up. Initially, the banner displays in the sidebar, but users can click a button to move it to the main content area.

Here's what happens with a naive implementation:

import { Component, signal } from '@angular/core';
import { PromoBannerComponent } from './promo-banner.component';

@Component({
  selector: 'app-root',
  imports: [PromoBannerComponent],
   styles: [
    `
  .bottom {
    display: flex;
  justify-content: center
  align-items: center;
  height: 100vh; 
  }
`,
  ],
  template: `
    <div class="dashboard">
      <header>
        <button (click)="toggleRegion()">Toggle Banner Position</button>
      </header>

      <div class="layout">
        @if (dockRight()) {
          <main>
            <app-promo-banner />
          </main>
        }

         <aside class="bottom">
          @if (!dockRight()) {
            <app-promo-banner />
          }
        </aside>
      </div>
    </div>
  `
})
export class AppComponent {
  dockRight = signal(false);

  toggleRegion() {
    this.dockRight.update(value => !value);
  }
}

When you click the toggle button, the banner moves—but the heart button resets and the timer starts over from zero. Why?

Because you're not actually moving the component. You're destroying it in one location and creating a brand new instance in another. The conditional rendering removes the component from the DOM entirely, then Angular initializes a fresh instance elsewhere.

Think of it like moving houses. You're not picking up your house and relocating it—you're demolishing it, then building an identical new house somewhere else. Everything inside gets lost in the process.

Can we do better? Let's explore three different approaches.


Approach 1: Using ngTemplateOutlet

The first instinct might be to use Angular's ngTemplateOutlet directive. This lets you define a template once and stamp it out in multiple locations. Sounds promising, right?

Here's how you'd implement it:

import { Component, signal } from '@angular/core';
import { NgTemplateOutlet } from '@angular/common';
import { PromoBannerComponent } from './promo-banner.component';

@Component({
  selector: 'app-root',
  imports: [NgTemplateOutlet, PromoBannerComponent],
  styles: [
    `
  .bottom {
    display: flex;
  justify-content: center
  align-items: center;
  height: 100vh; 
  }
`,
  ],
  template: `
    <div class="dashboard">
      <header>
        <button (click)="toggleRegion()">Toggle Banner Position</button>
      </header>

      <ng-template #promoBanner>
        <app-promo-banner />
      </ng-template>

      <div class="layout">
        @if (dockRight()) {
          <main>
            <ng-template [ngTemplateOutlet]="promoBanner" />
          </main>
        }

         <aside class="bottom">
          @if (!dockRight()) {
            <ng-template [ngTemplateOutlet]="promoBanner" />
           }
          </aside>        
      </div>
    </div>
  `
})
export class AppComponent {
  dockRight = signal(false);

  toggleRegion() {
    this.dockRight.update(value => !value);
  }
}

You define the banner component once inside an ng-template with a template reference variable. Then you use ngTemplateOutlet to render it in either location based on the condition.

This feels like it should work. You're reusing the same template definition, so surely the state should persist?

Unfortunately, no. The state still resets when you toggle the position. Click the heart, move the banner, and watch it reset.

Here's why: ngTemplateOutlet creates a new embedded view each time it attaches. You're reusing the template definition, but Angular still creates a fresh component instance every time. New view equals new component instance equals new state.

It's like having a blueprint for a house. Sure, you're using the same blueprint in both locations, but you're still building a new house from scratch each time.


Approach 2: CDK Template Portal

Angular CDK provides a Portal module with more sophisticated ways to move content. Let's try the Template Portal approach.

First, you need to install Angular CDK if you haven't already:

npm install @angular/cdk

Now let's refactor our component to use a Template Portal:

The complete, code-heavy deep dive (with diagrams, explanations, and tests) is published.

Read the full article