Tuesday, February 11, 2020

handing template gunk from one component to another in an Angular application when there is a middleman component to pass through

I am making sort of a generic grid sort of centered around the Angular Material paginated list. A user may specify both rows and columns and the columns may be of a number of "types" like so:

<ng-container [ngSwitch]="column.type">
   
   
<!-- Copy -->
   <ng-container *ngSwitchCase="0">
      {{record[column.name] | findValue:column}}
   </ng-container>
   
   
<!-- Hyperlink -->
   <ng-container *ngSwitchCase="1">
      <a [href]="record[column.hyperlinkUrl]">{{record[column.name] | findValue:column}}
            </a>
   </ng-container>
   
   
<!-- Button -->
   <ng-container *ngSwitchCase="2">
      <a href="#" (click)="runEventNotHyperlink(column.buttonClickEvent, record,
            dataSource.data)">{{record[column.name] | findValue:column}}</a>
   </ng-container>
   
   
<!-- Template -->
   <ng-container *ngSwitchCase="3">
      <ng-container *ngTemplateOutlet="templateInstance; context:
            {communicatedColumn: column, communicatedRecord: record}">
      </ng-container>
      <ng-content></ng-content>
   </ng-container>
   
</ng-container>

 
 

Alright, the ngSwitch above shows off what gets barfed into the cell where a particular row and column intersect and the interesting thing to note here is the last of the possibilities wherein someone using the grid may hand in a template. In the TypeScript class for the grid component we have "grid" as a selector and a ContentChild like so:

@ContentChild('templateReference', {read: TemplateRef, static: true}) templateInstance:
      ContentChild;

 
 

Alright, here is an example of nesting the repurposable grid in a larger component and handing in a template for defining what the template columns should look like. Obviously, there could be some ngSwitch logic here as well in the name of swapping between "which column" if you need two custom columns to behave differently.

<h1>Distributors</h1>
<grid [contents]="gridDataWrapper">
      <ng-template #templateReference let-column="communicatedColumn"
            let-record="communicatedRecord">
      <span>{{record[column.name]}}</span>*
      </ng-template>
</grid>

 
 

You can see what this does, no? With the exception of adding a span tag around the cell's contents it just puts an asterisk after what would otherwise be in the cell. I guess the span tag allows for some overarching skinning of the other contents and the asterisk independently. Meh. Alright, in some cases we want a series of these grids to be wrapped up together beneath a set of tabs. The set of tabs should also be a reusable component and it shows one grid at a time like so:

<div class="outerwrapper">
   <div class="topbartabs">
      <ul class="tabs">
         <li *ngFor="let tab of contents; let i = index;" [ngClass]="i==currentTab ? 'activetab'
               : ''"><a href="#" (click)="tabClick(i)">{{tab.tabName}}</a></li>
      </ul>
   </div>
   <grid [contents]="gridDataWrapper">
      <ng-template #templateReference let-column="communicatedColumn"
            let-record="communicatedRecord">
         <ng-container *ngTemplateOutlet="tabInstance; context:
               {communicatedTabColumn: column, communicatedTabRecord: record}">
         </ng-container>
      </ng-template>
   </grid>
</div>

 
 

"grid-tabs" is the selector for this component and in the component's TypeScript we have:

@ContentChild('tabReference', {read: TemplateRef, static: true}) tabInstance:
      ContentChild;

 
 

How do we communicate a template into this from a wrapping component that will bleed all of the way down to the grid component? We do so like so:

<h1>My Profile</h1>
<grid-tabs [contents]="tabsDataWrapper">
   <ng-template #tabReference let-tabcolumn="communicatedTabColumn"
         let-tabrecord="communicatedTabRecord">
      <span>{{tabrecord[tabcolumn.name]}}</span>*
   </ng-template>
</grid-tabs>

 
 

As I type this up, I wonder if two grids in two tabs could have two columns of the same name which needed different templates. I guess one would have to rename a column upfront before assigning a collection of any to one of the grids to accommodate for that. That kinda sucks, but should I get into gold platting to compensate for that heartache?

No comments:

Post a Comment