title: Change detection not working when creating a dynamic component with nested input data
body: <p>I have an issue with change detection not firing the child <code>ngOnChanges</code> method for child components created dynamically using angular 13.</p>
  <p>Here i have two dynamic components mainly</p>
  <ul>
  <li>Button Block</li>
  <li>Text Block</li>
  </ul>
  <p>Initially when the application loads the Button block is loaded. Then on click of a button i can change that to a text block. And another button to change the details of a the loaded block is added which is not working.</p>
  <p>renderer-component.ts</p>
  <pre class="lang-js prettyprint-override"><code>@Component({
    selector: 'app-renderer',
    templateUrl: './renderer.component.html',
    styleUrls: ['./renderer.component.css'],
  })
  export class RendererComponent implements OnInit {
  
    currentData: IBlock;
  
    constructor() {}
  
    ngOnInit() {
      this.mountButton();
    }
  
    mountButton() {
      this.currentData = new ButtonBlock({ type: 'button', data: 'Button text',
        attribute: { color: 'red' },
      });
    }
  
    mountText() {
      this.currentData = new TextBlock({ type: 'text', data: 'Hello world',
        attribute: { color: 'green' },
      });
    }
  
    // This is to update the component data
    updateData() {
      this.currentData.data = `Updated ${this.currentData.type}`;
      this.currentData.attribute = { color: 'yellow' };
      const data = { ...this.currentData };
  
      this.currentData = { ...data };
    }
  }
  
  </code></pre>
  <p>dynamic-loader.component</p>
  <pre class="lang-js prettyprint-override"><code>@Component({
    selector: 'app-dynamic-loader',
    templateUrl: './dynamic-loader.component.html',
    styleUrls: ['./dynamic-loader.component.css'],
  })
  export class DynamicLoaderComponent implements OnInit, OnChanges {
    @Input() data: IBlock;
  
    @ViewChild('viewContainerRef', { read: ViewContainerRef, static: true })
    public containerRef: ViewContainerRef;
  
    compMaps = [
      { key: 'button', component: ButtonBlockComponent },
      { key: 'text', component: TextBlockComponent },
    ];
  
    private componentRef: ComponentRef&lt;any&gt;;
  
    constructor() {}
  
    ngOnInit() {}
  
    ngOnChanges(changes: SimpleChanges): void {
      const dataToUpdate = { ...this.data };
  
      if (this.componentRef) {
        if (this.componentRef.instance.data.type === dataToUpdate.type) {
          console.log('--update trigger--');
          this.updateComponentData(dataToUpdate);
        } else {
          console.log('--load trigger--');
          this.loadComponent(dataToUpdate);
        }
      } else {
        console.log('--load trigger--');
        this.loadComponent(dataToUpdate);
      }
    }
  
    /**
     * Mount component
     */
    loadComponent(data: any) {
      // Get the component to render
      const componentMap = this.compMaps.find((comp) =&gt; comp.key === data.type);
  
      // Clear any previous references
      this.containerRef.clear();
  
      if (componentMap) {
        this.componentRef = this.containerRef.createComponent(componentMap.component);
  
        // Pass data to the component
        this.componentRef.instance['data'] = { ...data };
      }
    }
  
    /**
     * Update data of an already mounted component
     */
    updateComponentData(data: any) {
      // Pass data to the component
      this.componentRef.instance['data'] = { ...data };
    }
  }
  
  </code></pre>
  <p>text-block-component.ts</p>
  <pre class="lang-js prettyprint-override"><code>@Component({
    selector: 'app-text-block',
    templateUrl: './text-block.component.html',
    styleUrls: ['./text-block.component.css'],
  })
  export class TextBlockComponent implements OnInit, OnChanges {
    _data: IBlock;
  
    @Input() set data(d: IBlock) {
      this._data = { ...d };
    }
  
    get data() {
      return this._data;
    }
  
    styles: Record&lt;string, string&gt;;
  
    constructor() {}
  
    // Fired first time on component mount
    ngOnInit() {
      console.log('--ngOnInit-TextBlockComponent--', this._data);
      this.styles = this._data.attribute;
    }
  
    // This is not firing when `updateComponentData` is called
    ngOnChanges(changes: SimpleChanges) {
      console.log('--ngOnChanges-TextBlockComponent--', this._data);
      this.styles = this._data.attribute;
    }
  }
  
  </code></pre>
  <p>button-block-component.ts</p>
  <pre class="lang-js prettyprint-override"><code>export class ButtonBlockComponent implements OnInit, OnChanges {
    _data: IBlock;
  
    @Input() set data(d: IBlock) {
      this._data = { ...d };
    }
  
    get data() {
      return this._data;
    }
  
    styles: Record&lt;string, string&gt;;
  
    constructor() {}
  
    // Fired first time on component mount
    ngOnInit() {
      console.log('--ngOnInit-ButtonBlockComponent--', this._data);
      this.styles = this._data.attribute;
    }
  
    // This is not firing when `updateComponentData` is called
    ngOnChanges(changes: SimpleChanges) {
      console.log('--ngOnChanges-ButtonBlockComponent--', this._data);
      this.styles = this._data.attribute;
    }
  }
  </code></pre>
  <p>As per my requirement when the <code>updateData</code> method from <code>renderer-component</code> is called on an already mounted component (text or button) the <code>ngOnChanges</code> inside the text or button component needs to be invoked.</p>
  <p>I also tried enabling the manual change detection for this but it doesn't seem to work either.</p>
  <p>Here is a minimal reproduction of the issue <a href="https://stackblitz.com/edit/angular-ivy-aacr6p?file=src%2Fapp%2Fdynamic%2Fdynamic-loader%2Fdynamic-loader.component.ts" rel="nofollow noreferrer">Dynamic component change detection issue</a>. You can check the console log to see the details</p>