Angular 6 - Multiple child components should be of same instance
Asked Answered
A

4

7

I simplified my problem:

<div *ngIf="layout1" class="layout1">
  <div class="sidebar-layout1">
     some items
  </div>
  <child-component [something]="sth"></child-component>
</div>
<div *ngIf="!layout1" class="layout2">
  <child-component [something]="sth">
    <p>some content...</p>
  </child-component>
</div>

I have a parent component which has the possibility of a normal layout (layout1) and a fullscreen layout(layout2) (In fullscreen mode the child-component should be in fullscreen). The problem is, when i change layout with *ngIf, the child-component is destroyed and a new one is generated. I want to have the same instance and don't loose important informations of child-component and avoid some api calls.

Is there any way to achive that the child-component will not be destroyed or is there a better way than ngIf?

I just need one instance of child-component for different layouts in a parent-component.

Aleksandrovsk answered 26/6, 2018 at 7:35 Comment(4)
but using [hidden] still occupies the space. instead, set display:none on ngStyle. its just my assumption. just give a try. and i need to know ''!layout1" is that any flag or boolen?Eleen
layout1 is just a boolean flag which i update on a button click eventAleksandrovsk
okay. try this. add one more flag like if(this.paraentLayout == false){ dont made change in child} i.e *ngIf == ' parentLayout == false ? classA : ClassB'Eleen
I'll use only one child and ngClass < child-component [ngClass]="{'layout1':layout1,'layout2':!layout1}" ></child-component>Omega
G
3

As you may have noted, If you hide elements using *ngIf then a new component is created. This is what we will try to focus on and try to avoid creating a new component.

For this, we can use a 'switcher layout' and pass the child component as content

<app-layout-switcher [layout1]="layout1">
  <ng-container>
    <child-component
      *ngIf="sth$ | async as sth; else loading"
      [something]="sth"
    >
      <p>some content...</p>
    </child-component>
    <ng-template #loading>
      <h1>Loading...</h1>
    </ng-template>
  </ng-container>
</app-layout-switcher>

I have added a mock http call to show the loading.

In our app-layout-switcher component we can switch between the layout as desired. We will pass the child-component into a template to be able to reuse it in the layout

<div *ngIf="layout1">
  <app-layout-1>
    <ng-template [ngTemplateOutlet]="childComponent"></ng-template>
  </app-layout-1>
</div>

<div *ngIf="!layout1">
  <app-layout-2>
    <ng-template [ngTemplateOutlet]="childComponent"></ng-template>
  </app-layout-2>
</div>

<ng-template #childComponent>
  <ng-content></ng-content>
</ng-template>

Now we can use the template in our layouts

<header>
  <h1>Layout 1</h1>
</header>
<main>
  Contents in Layout 1
  <div>
    <ng-content></ng-content>
  </div>
</main>

<footer>Layout 1 Footer</footer>

We are now using only one instance of the component. To confirm this I have added a textfield in the demo. You will notice that data is persisted when switching the layout

See this Demo

Gardia answered 1/10, 2021 at 6:15 Comment(1)
hi @Owen Kelvin. Thanks for you answer. It works fine for one component. But how does it work for multiple child components that use select in the <ng-content> tags? It seems that the select tag is lost in the layout switcher.Weixel
U
0

Use [hidden] attribute instead with the reverse logic, it will prevent the element destroying.

<div [hidden]="!layout1" class="layout1">
...
</div>
<div [hidden]="layout1" class="layout2">
...
</div>

I hidden just hides/shows the DOM element with css by changing display style

Undertaking answered 26/6, 2018 at 7:42 Comment(2)
but using [hidden] still occupies the space. instead, set display:none on ngStyle. its just my assumption. just give a tryEleen
but i have still two different instances of my child-component this way. I need a way to have just one instance of child component to not loose informations of itAleksandrovsk
D
0

You can achieve that in a few steps:

  1. Create a service using this command:
ng generate service data-passing
  1. Define two variables in that service that holds your data for each component:
import {Injectable} from '@angular/core';

@Injectable({
  providedIn: 'root',
})
export class DataPassingService {
  public firstComponentData;
  public secondComponentData;

  constructor() { }

}
  1. Use service in your component:
import {DataPassingService} from '...';

...
constructor(public dataPassingService: DataPassingService) {
}
  1. Store each component data in relative variable:
setDate(first, second) {
  this.dataPassingService.firstComponentData = first;
  this.dataPassingService.secondComponentData = second;
}
  1. Use *ngIf as you used before to control components visibility:
<div *ngIf="layout1" class="layout1">
  <div class="sidebar-layout1">
     some items
  </div>
  <child-component [something]="dataPassingService.firstComponentData"></child-component>
</div>
<div *ngIf="!layout1" class="layout2">
  <child-component [something]="dataPassingService.secondComponentData">
    <p>some content...</p>
  </child-component>
</div>
Deserving answered 30/9, 2021 at 7:4 Comment(0)
G
0

As you want to display the same/different details within two different layouts:

  • Implement akita store for state management https://datorama.github.io/akita/docs/store
  • Get all data required from service in parent component itself.
  • Update the received data from service into the store.
  • Subscribe to stores by using queries in both layouts.
  • Update the latest updates made by user in store.
Genesia answered 2/10, 2021 at 7:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.