1
votes

I'm working on a compare view with expansion panels of Angular Material.

It's dynamically rendered depending on how many dogs/parts I'm comparing, setting columns in a mat-grid-list who contains parts that can be compared, as expansion panels.

<h2 class="dogs-comparison--header">dogs Comparison</h2>
<mat-grid-list [cols]="dogs.length" rowHeight="20:1" *ngIf="!isLoading">
  <mat-grid-tile *ngFor="let dog of dogs" colspan="1" rowspan="2" layout="layout-fill">
    <mat-grid-tile-header class="column-header">
      {{dog['title']}}
    </mat-grid-tile-header>
    <mat-accordion multi="true" class="dog-compare--dog_parts">
      <mat-expansion-panel *ngFor="let part of dog['parts']" [expanded]="part.isExpanded">
        <mat-expansion-panel-header>
          <mat-panel-title>
            {{ part.partTitle}}
          </mat-panel-title>
        </mat-expansion-panel-header>
        <p *ngFor="let item of part['items']">
          {{item.itemTitle}}: <span>{{item.itemValue}}</span>
        </p>
      </mat-expansion-panel>
    </mat-accordion>
  </mat-grid-tile>
</mat-grid-list>

My question is : is there any way that I could, when clicking one of the parts as expansion panel in one column, open the adjacent column's expansion panels. So let's say Dog has a part called Anatomy, I compare Dog1, Dog2 and Dog3, If I toggle Dog1 Anatomy expansion panel, the two others would toggle as well ?

I'm struggling a bit, checking on how I can have dynamic/similar IDs but I'm stuck on the question for now.

Thank you for the help

1

1 Answers

1
votes

It's just a matter of getting the logic right. You are really just binding expanded to a complex expression that returns the state appropriate to whether or not the dog is being compared. You need to add the logic for that expression and also logic for handling expansion panel expand/collapse operations, which also depend on the compare state of the dog. Something like:

<mat-grid-tile-header class="column-header">
    {{dog['title']}}&nbsp;&nbsp;
    <mat-checkbox 
        [checked]="dog.compare" 
        (change)="compare(dog, $event.checked)">compare</mat-checkbox>
</mat-grid-tile-header>
<mat-accordion multi="true" class="dog-compare--dog_parts">
    <mat-expansion-panel *ngFor="let part of dog['parts']; index as i" 
        [expanded]="isExpanded(dog, part, i)" 
        (opened)="togglePart(dog, part, i, true)"
        (closed)="togglePart(dog, part, i, false)">
...

expandedParts = { };

togglePart(dog, part, index, expanded) {
  if (dog.compare) {
    this.expandPart(index, expanded);
  } else {
    part.expanded = expanded;
  }
}

compare(dog, compare) {
  if (compare) {
    let alreadyComparing = false;  
    this.dogs.forEach( (item) => {
      alreadyComparing = alreadyComparing || item.compare;
    });
    if (!alreadyComparing) {
      dog.parts.forEach( (part, index) => {
        this.expandedParts[index.toString()] = part.expanded;
      });
    }
    dog.compare = compare;
  } else {
    dog.compare = compare;
    let stillComparing = false;  
    this.dogs.forEach( (item) => {
      stillComparing = stillComparing || item.compare;
    });
    if (!stillComparing) {
      this.expandedParts = { };
    }
  }
}

isExpanded(dog, part, index) {
  if (dog.compare) {
    return !!this.expandedParts[index.toString()];
  } else {
    return !!part.expanded;
  }
}

expandPart(index, expanded) {
  this.expandedParts[index.toString()] = expanded;
}

Here it is on Stackblitz. (Sorry - layout is a bit messy.)

This might not be exactly what you want, but hopefully you can use it as a start.