Search code examples
htmlcssangularmat

how do i create mat expansion using angular with exact UI


<div class="row">
    <div class="col-lg-6 col-md-6 col-sm-12 mt-3" *ngFor="let item of autoPanel; let idx = index">
        <!-- INDEX MAPPING OF ARRAY -->
        <mat-expansion-panel class="ml-2 mr-2" style="width: -webkit-fill-available"
            (click)="getCurrentKPIName(item,idx)">
            <mat-expansion-panel-header>
                <mat-panel-title class="d-flex align-items-center justify-content-between">
                    {{ item.name }}
                </mat-panel-title>
            </mat-expansion-panel-header>
        </mat-expansion-panel>
    </div>
</div>

I have created dynamic mat expension using angular Img..

whenever i expand the any of the card in other side i got some space how do i remove that space. can you please help me out of this. thanks in advance...

Exact UI what i need...


Solution

  • Due to the flex on the row, we cannot achieve this effect. If you are certain it's a two column layout then you need two rows, each 50% width, then run *ngFor on each of the rows. I use *ngIf="idx % 2 === 0" and the opposite condition to render the odd rows on the left side and the even ones on the right side.

    <div class="row">
      <div class="col-lg-6 col-md-6 col-sm-12 mt-3">
        <div class="row">
          <ng-container *ngFor="let item of autoPanel; let idx = index">
            <div class="col-lg-12 col-md-12 col-sm-12 mt-3" *ngIf="idx %2 === 0">
              <mat-expansion-panel
                class="ml-2 mr-2"
                style="width: -webkit-fill-available"
              >
                <mat-expansion-panel-header>
                  <mat-panel-title
                    class="d-flex align-items-center justify-content-between"
                  >
                    {{ item.name }}
                  </mat-panel-title>
                </mat-expansion-panel-header>
              </mat-expansion-panel>
            </div>
          </ng-container>
        </div>
        <!-- INDEX MAPPING OF ARRAY -->
      </div>
      <div class="col-lg-6 col-md-6 col-sm-12 mt-3">
        <div class="row">
          <ng-container *ngFor="let item of autoPanel; let idx = index">
            <div class="col-lg-12 col-md-12 col-sm-12 mt-3" *ngIf="idx %2 !== 0">
              <mat-expansion-panel
                class="ml-2 mr-2"
                style="width: -webkit-fill-available"
              >
                <mat-expansion-panel-header>
                  <mat-panel-title
                    class="d-flex align-items-center justify-content-between"
                  >
                    {{ item.name }}
                  </mat-panel-title>
                </mat-expansion-panel-header>
              </mat-expansion-panel>
            </div>
          </ng-container>
        </div>
        <!-- INDEX MAPPING OF ARRAY -->
      </div>
    </div>
    

    Stackblitz Demo


    Alternative solution:

    We can use a library called, Masonry.js to achieve these dynamic heights.

    First import the necessary imports, for me it's Bootstrap and Masonry:

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8" />
        <title>Basic expansion panel</title>
        <base href="/" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <link rel="preconnect" href="https://fonts.gstatic.com" />
        <link
          href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap"
          rel="stylesheet"
        />
        <link
          href="https://fonts.googleapis.com/icon?family=Material+Icons"
          rel="stylesheet"
        />
        <link
          href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
          rel="stylesheet"
          integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH"
          crossorigin="anonymous"
        />
        <script
          src="https://cdn.jsdelivr.net/npm/[email protected]/dist/masonry.pkgd.min.js"
          async
        ></script>
      </head>
      <body class="mat-typography mat-app-background">
        <expansion-overview-example></expansion-overview-example>
        <div style="margin-top: 24px">Current build: 18.0.2</div>
    
        <!-- Optional JavaScript -->
        <!-- jQuery first, then Popper.js, then Bootstrap JS -->
        <script
          src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
          integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
          crossorigin="anonymous"
        ></script>
        <script
          src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js"
          integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49"
          crossorigin="anonymous"
        ></script>
        <script
          src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js"
          integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy"
          crossorigin="anonymous"
        ></script>
      </body>
    </html>
    

    Then add the data attribute to the grid to enable Masonry for it:

    <div class="row grid" data-masonry='{"percentPosition": true }' #masonry>
    

    Then on the onclick event, refresh the list, using the below code:

      click(masonry: any) {
        const intervalRef = setInterval(() => {
          new (window as any).Masonry('.grid', this.masonryProps).reloadItems();
        }, 10);
        setTimeout(() => {
          clearInterval(intervalRef);
        }, 1000);
      }
    

    Stackblitz Demo