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.
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.
When dropdown arrow is clicked cards are resized to take 2 cells and push the next members over.
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.
FREE CONSULTATION
Hire our experts to build a dedicated project. We'll analyze your business requirements, for free.
Answered
- 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
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?