Holiday Notice: Support will be provided on a limited scale from December 24th, 2024, to January 2nd, 2025. Happy holidays and a wonderful New Year!


Topic: Anyone know an example of how to create a dynamic expanding/collapsing card grid?

Spencer LeBlanc free asked 5 years ago


So apparently have been failing on my Google-fu to find the right term or example for this. What I'm trying to do is create a grid where each cell holds a card with some preview info. What I want to have happen is say on a 3x3 grid of cards where clicking some the card(1,3) would cause it to expand and show more information and while it's height and width increases it either pushes itself to the next row and/or pushes other card after into the next row, or alternatively if at the bottom row, pushes card to a newly created row below it. I have no idea what the right term for this would be but would appreciate an example of this or an idea of how to go implement resizing cards or changing col- row- size dynamically.


Arkadiusz Idzikowski staff commented 5 years ago

It might be good idea to take a look at CSS grid in this case. Is there any live preview example of this kind (or similar) implementation?


Spencer LeBlanc free answered 5 years ago


Here's some example frames showing the expansion of cards on a grid with some dummy names used. Tried producing live version of example through stackblitz but it relies on multiple components/module for the card, row, and root; and does several calls to a live server for info that'd be too extensive to find and replace all those references with a service. My apologies. unexpanded cards

When dropdown arrow is clicked cards are resized to take 2 cells and push the next members over. expanded cards on hitting drop down arrow next to phone symbol

Relevants html/ts parts

Root html

<!-- use hidden instead of ngif so that the images only have to load once while in table view instead of loading for cards -->
<!--card part-->
<div [hidden]="!showCards" *ngIf="!reset">
  <div class="row justify-content-center">
    <ng-container *ngFor="let employee of allEmployees; let i = index; first as first">
       <app-employee-card  [hidden]="!employeeDisplayed(employee)" class="card-container" [ngClass]="employee.expanded ? 'col-xl-6 col-md-6 col-sm-12' : 'col-xl-3 col-md-4 col-sm-6'" [class.transition] = "transitioning" [employee]="employee" [columns]="columns" [editAbility]="isAdmin || isSelf(employee)" (changedEmployee)="employeeChanged($event)" (successAlert)="showSuccess($event)" (errorAlert)="showError($event)" (doubleSize)="employee.expanded=!employee.expanded;transition()"></app-employee-card>
    </ng-container>
  </div>
</div>   

relevant root ts function

//allows smooth transition when card is expanded transition(){

this.transitioning=true;
let parent = this;
this.changeDetector.detectChanges();
setTimeout(()=>{
  this.transitioning=false;

}, 1000)

}

A card is just defined in html as

<div >



<mdb-card class="testimonial-card">
    <div class="card-up card-background"></div>
    <mdb-card-body>
        <mdb-card-title>
            <div class="circuit-background-container">
                <div class="content">
                    <div class="avatar mx-auto" >
                        <input *ngIf="editAbility" type="file" accept=".png, .jpg, .jpeg" style="display: none;" id="{{isModal ? employee.first_name+employee.last_name+'ProfileImageModal' : employee.first_name+employee.last_name+'ProfileImage'}}" (change)="uploadImage($event)">
                        <label for="{{isModal ? employee.first_name+employee.last_name+'ProfileImageModal' : employee.first_name+employee.last_name+'ProfileImage'}}" [class.changeImage]="editAbility">

                            <img (load)="imageLoaded=true" [src]="imageSrc" class="rounded-circle" />

                            <!-- <object (load)="imageLoaded = true;" type="image/png" width="110" height="" [data]="imageSrc"></object> -->



                        </label>
                        <mdb-spinner [hidden]='!loading' class="image-loader"></mdb-spinner>
                        <i *ngIf='imageLoaded' class="camera-backdrop fas fa-camera fa-3x"></i>

                    </div>

                    <h4>
                        {{employee?.first_name}} {{employee?.last_name}}
                        <span class="editBtn" *ngIf="editAbility&&expanded">
                            <i (click)="enableEditing()" class="fas" [ngClass]="editMode ? 'fa-cloud-upload-alt' : 'fa-user-edit'"></i>
                        </span>
                    </h4>
                    <div class="links">
                        <!-- <a href="{{'mailto:' + employee.email_address}}"><i class="far fa-envelope"></i></a>
                        <a href="{{'tel:' + employee.phone_number_cell}}"><i class="fas fa-phone"></i></a> -->
                        <a (click)="expandedCard.toggle();expandCard();"><i class="fas expandBtn" [ngClass]="expanded ? 'fa-chevron-up' : 'fa-chevron-down'"></i></a>
                    </div>
                </div>  
            </div>
        </mdb-card-title>

        <!-- <div mdbCollapse #expandedCard="bs-collapse">

            <hr >

            <div class="employee-data-container row" >

                <ng-container *ngFor="let col of columns; let i = index" >
                    <div class="col-sm-6 employee-data" *ngIf="col.cardDisplay && findValue(col.attributes)">
                        <div *ngIf="!editMode">
                            <span class="font-weight-bold">{{col.header + ":"}}</span>
                            {{findValue(col.attributes)}}
                        </div>
                        <div *ngIf="editMode" [class.edited]="col.changed">
                            <span class="font-weight-bold">{{col.header + ": "}}</span>
                            <div *ngIf="!col.dropdown; else dropdown" class="md-form editDb">
                                <input type="text" class="form-control form-control-md" mdbInput value="{{findValue(col.attributes)}}" (keyup)="valueChanged($event, col)" (keypress)="blur($event)">
                            </div>
                            <ng-template #dropdown>
                                <div class="md-form editDb">

                                    <select class="browser-default form-control form-control-md" (change)="valueChanged($event, col)">
                                        <option *ngFor="let option of col.dropdown" [value]="option.value" [selected]="option.name === findValue(col.attributes)" >{{option.name}}</option>
                                    </select>
                                </div>
                            </ng-template>
                        </div>
                    </div>
                </ng-container>


            </div>
        </div>
         -->

    </mdb-card-body>
</mdb-card>

and just a snippet of the ts dealing with expand check and edit

e//updates card when user presses input button
  enableEditing(){
if(this.editAbility){

  if(this.editMode){
    this.saveChanges();
  }
  this.editMode =! this.editMode;
  this.changeDetector.detectChanges();

    }
  }

  //ensures persistance across ids
  calcInputId(column){
return column.attributes[0].split('.')[0];
  }

  //focuses out of input box if user presses enter
  blur(event){
    if(event.which == 13){
  event.target.blur();
}
  }

  //pushes update to the clent side for persistance
  updatedImage(updatedEmployee: Employee) {
this.loading = false;

// this.imageSrc = 'https://drive.google.com/uc?id=' + updatedEmployee.profile_image;
// this.setImageSrc(updatedEmployee.profile_image);
this.changeDetector.detectChanges();

this.successAlert.emit("Successfuly Updated " + this.employee.first_name + " " +             this.employee.last_name + "'s Profile Picture");

this.employee.profile_image = updatedEmployee.profile_image;

this.changedEmployee.emit(this.employee);

  }

  expandCard(){
this.expanded=!this.expanded;
this.changeDetector.detectChanges();

//changes width of the card when its expanded
this.doubleSize.emit(this.expanded)
  }

and just a minor bit of css that affect the transition animation

.transition{
transition: 1s
}

Sorry for that hacked and chopped code blocks, there is a lot other ancillary functionallity that I leave out, am just looking to recreate the scheme of resizing cards to some extant or by other means with just a blank card that expands/contracts on a click event.

Also unrelated FYI: the image uploader in the text editor of reply seems to be case sensitive and does not want to recognize .PNG as .png format, don't know if this is intentional or a bug, on windows some pictures list the format with caps when in explorer and had to rename to the lower for it to register.



Please insert min. 20 characters.

FREE CONSULTATION

Hire our experts to build a dedicated project. We'll analyze your business requirements, for free.

Status

Answered

Specification of the issue

  • ForumUser: Free
  • Premium support: No
  • Technology: MDB Angular
  • MDB Version: 8.3.0
  • Device: PC
  • Browser: Chrome
  • OS: Windows
  • Provided sample code: No
  • Provided link: No