7

I have 2 different components where I am using Angular - Expansion Panel for expandable summary view.

I am able to integrate <mat-expansion-panel> to individual components successfully.

I need help to make Component2.html as parent of Component1.html (Expand within expand- Please see below Image)enter image description here

  • Component 1 should be able to expand and collapse independently to show data

  • Component 2 should embed Component 1 within itself, so when Component 1 is expanded it can show its data and display remaining Child components

NOTE - Both the component has Sibling relation, no parent child or child - parent

Component1.html

  <div class="row">
    <div class>
      <dl class="row property_set" data-property-set-name="data">
        <mat-accordion>
          <mat-expansion-panel (opened)="doExpand = true"
                             (closed)="doExpand = false">
          <mat-expansion-panel-header>
            <mat-panel-title>
        <dt class="col-sm-4 record_property">data</dt>
      </mat-panel-title>
      <mat-panel-description>
        <dd class="col-sm-8 record_property_value data_name" id="{{genId(data.name)}}">
          <inline-misal-edit 
                        [(field)]="data.name" [elementType]="a.bName" (fieldChange)="dataModified(data)"
                        cols="30" rows="1"></inline-misal-edit>
          </dd>
      </mat-panel-description>
    </mat-expansion-panel-header>

        <dt class="col-sm-4 record_property">news</dt>
        <dd class="col-sm-8 record_property_value">{{data.news?.created | news}}</dd>
      </mat-expansion-panel>
    </mat-accordion>
      </dl>
    </div>

Component2.html


  <dl class="row property_set" data-property-set-name="misal">
    <mat-accordion>
        <mat-expansion-panel (opened)="doExpand = true"
                             (closed)="doExpand = false">
          <mat-expansion-panel-header>
            <mat-panel-title>
              misal Id
            </mat-panel-title>
            <mat-panel-description>
              <dd class="col-sm-10 record_property_value" data-property-type="select">{{misal.id || 'new'}}</dd>
            </mat-panel-description>
          </mat-expansion-panel-header>
          <dd class="col-sm-10 record_property_value misal_name">{{misal.data[0].name}}</dd>
          <dt class="col-sm-2 record_property">Country Pass</dt>
          <dt class="col-sm-2 record_property">Plugins Program</dt>
          <dd class="col-sm-10 record_property_value">
            <north-dhamma[(misal)]="misal" [editMode]="editMode" (misalChange)="recordModified.emit()"></registry-number>
          </dd>
          <dt *ngIf="misal.value === 'hovered'" class="col-sm-2 record_property">Related Plugins Program</dt>
          <dd *ngIf="misal.value === 'hovered'" class="col-sm-10 record_property_value">
            <land-hole></land-hole>
          </dd>
                </mat-expansion-panel>
      </mat-accordion>
  </dl>

.ts file

  panelOpenState = true;                 

UPDATE

The answer given below by Robbie works for parent - child component relation but not for the sibling component

Tejas Mehta
  • 281
  • 1
  • 4
  • 17
  • Is this something you look https://stackoverflow.com/questions/48073057/open-close-sidenav-from-another-component/48076331#48076331 – Eldho Apr 26 '21 at 06:07
  • @Eldho This is what I am looking for - https://stackblitz.com/edit/angular-5euuwx?file=src%2Fapp%2Fexpansion-overview-example.html. This is working for `parent to child component`. In my case `both components are silbings` I am looking for solution that will work in my scenario – Tejas Mehta Apr 26 '21 at 06:13

4 Answers4

2

One way to do this is using a shared service - https://angular.io/guide/component-interaction#parent-and-children-communicate-via-a-service

However I find the following solution much simpler, it allows to share data between 2 siblings.

app-sibling2.component.ts

import { AppSibling1Component } from '../app-sibling1/app-sibling1.component';

export class AppSibling2Component {
   @Input() data: AppSibling1Component;
   ...
}

In you parent component template:

<!-- Assigns "AppSibling1Component" instance to variable "data" -->
<app-sibling1 #data></app-sibling1>
<!-- Passes the variable "data" to AppSibling2Component instance -->
<app-sibling2 [data]="data"></app-sibling2> 

I believe this is what you are looking for. Let me know if you have any questions

Ashish Shah
  • 1,047
  • 7
  • 17
1

You should be able to add your child component right after the close tag of mat-expansion-panel-header

<mat-accordion>
  <mat-expansion-panel>
    <mat-expansion-panel-header>
      <mat-panel-title>
        Parent Expansion
      </mat-panel-title>
    </mat-expansion-panel-header>
    <p>Content of parent</p>
    <!-- add child here -->
    <app-child></app-child>
  </mat-expansion-panel>
</mat-accordion>

https://stackblitz.com/edit/angular-5euuwx?file=src%2Fapp%2Fexpansion-overview-example.html

robbieAreBest
  • 1,601
  • 14
  • 16
  • Thanks for the answer, I mentioned the `2 components` in my project are not related `(they are side-by-side, SIBLINGS)`. They are separate, they `do not have parent to child or child 2 parent relation`. Can you help me out how can I tackle this case? – Tejas Mehta Apr 23 '21 at 13:04
0

I am bit confused over there you want Component2.html as parent of Component1.html and you mentioned both the component has Sibling relation, no parent child or child - parent.

Keeping that in mind how about having a ExpansionWrapperComponent that wraps both Component1 and Component2 and incorporates the behavior - if Component2 is toggled Component1 must get toggled at the same time Component1 can be toggled separately too.

expansion-wrapper.component.html

<div class="expansion-wrapper">
  <div class="parent">
    <ng-content select="app-component2"></ng-content>
  </div>
  <div class="child">
    <ng-content select="app-component1"></ng-content>
  </div>
</div>

expansion-wrapper.component.ts

import { AfterContentInit, Component, ContentChild, OnInit } from '@angular/core';
import { Component1Component } from '../component1/component1.component';
import { Component2Component } from '../component2/component2.component';

@Component({
  selector: 'app-expansion-wrapper',
  templateUrl: './expansion-wrapper.component.html',
  styleUrls: ['./expansion-wrapper.component.css']
})
export class ExpansionWrapperComponent implements OnInit, AfterContentInit {

  @ContentChild(Component2Component, { static: false }) component2: Component2Component;
  
  @ContentChild(Component1Component, { static: false }) component1: Component1Component;

  constructor() { }

  ngOnInit() {
  }

  ngAfterContentInit() {
    this.component2.panelStateChanged.subscribe(res => {
      this.component1.togglePanelState(res);
    });
  }

}

Where Component1 and Component2 contains separate expansion panel. With this Component1 is a sibling of Component2 and feels like embeded into Component2.

Check the application over stackblitz

Pankaj Prakash
  • 2,300
  • 30
  • 31
0

I'm confused about what are your needs.

Component 2 should embed Component 1 within itself

What you are requiring is something like this

// component2.component.ts
@Component({
  selector: "component2",
  template: `
    <component1></component1>
  `,
  styles: []
})
export class Component2 {
}

Both the component has Sibling relation, no parent child or child - parent

But here, you want this.

// app.component.ts
@Component({
  selector: "app",
  template: `
    <component2></component2>
    <component1></component1>
  `,
  styles: []
})
export class AppComponent {
}

I guess what you want is something like this, demo. 2 sibling <mat-expansion-panel> as a display unit.

2

Ivan Tsai
  • 154
  • 1
  • 5