title: How to create a Material Design Select dropdown with option content that is dependent on option selection?
body: <p><strong>Background:</strong><br>
  For a project I'm working on, my team has a permission system that, for our end-users' sake, we want to describe what each level of permission entails.</p>
  
  <p>The way the team I'm on did this back in AngularJS Material Design, was that we simply included some additional HTML inside of each <code>md-option</code>, that was styled to hide if that particular <code>md-option</code> was selected.  We have since found that that does not work in Angular Material Design.</p>
  
  <p><strong>What We've Tried:</strong><br>
  First, was the original implementation, based on what our team used back in the AngularJS days:</p>
  
  <p><strong>Pass #1 - HTML/CSS in mat-option (DOES NOT WORK)</strong><br>
  <em>Markup:</em>  </p>
  
  <pre><code>&lt;mat-select name="SomePermissionDropdown"
              [(ngModel)]="permissionModel.somePermission"&gt;
    &lt;!-- 'None' has no description by design. --&gt;
    &lt;mat-option class="permission-option" value="0"&gt;
      None
    &lt;/mat-option&gt;
    &lt;mat-option class="permission-option" value="1"&gt;
      Make requests
      &lt;span class="permission-description"&gt;You can make requests, but you can't see anyone else's&lt;/span&gt;
    &lt;/mat-option&gt;
    &lt;mat-option class="permission-option" value="2"&gt;
      View requests
      &lt;span class="permission-description"&gt;You can make requests and view requests created by other people&lt;/span&gt;
    &lt;/mat-option&gt;
  &lt;/mat-select&gt;
  </code></pre>
  
  <p><em>SCSS:</em>  </p>
  
  <pre><code>.permission-option {
      font-weight: bold;
  
      .permission-description {
          display: block;
          margin-top: -24px;
          font-style: italic;
          font-weight: lighter;
          color: #666;
      }
  }
  
  mat-select mat-select-value-text .permission-description {
    display: none;
  }
  </code></pre>
  
  <p><em>Results of this approach:</em>  Whenever a record is loaded, or a value is selected, instead of the <code>permission-description</code> being hidden as expected, what one sees in the dropdown is text as below:</p>
  
  <pre><code>Make requests  You can make requests, but you can't see anyone else's
  </code></pre>
  
  <p>Basically, it appears as though when someone selects a <code>mat-option</code> in Angular Material Design's <code>mat-select</code>, that the text is taken, all HTML is stripped out, and the sanitized HTML is what gets placed in the actual <code>mat-select</code> text label.  I have been unable to find any way to override this behavior.</p>
  
  <p><em>Why this is bad:</em> The Angular team has literally taken functionality away that was present in AngularJS Material Design.</p>
  
  <p><strong>Pass #2 - Well, let's just strip the description text on an ad-hoc basis!</strong><br>
  We amended the <code>mat-select</code> from the first pass with a <code>(selectionChange)</code> event:</p>
  
  <pre><code>&lt;mat-select name="SomePermissionDropdown"
              (selectionChange)="onPermissionChanged($event)"
              ...&gt;
  </code></pre>
  
  <p>Where <code>onPermissionChanged</code> has the following component code:</p>
  
  <pre><code>onPermissionLevelChanged(event: any) {
    let text: string = event.source.triggerValue;
    let startTrimmingHere: number = text.indexOf('  ');
    if (startTrimmingHere === -1)
      return;
  
    let shortText: string = text.substring(0, startTrimmingHere - 1);
  
    // Update the text directly.
    event.source.trigger.nativeElement.parentNode.children[0].textContent = shortText;
  }  
  </code></pre>
  
  <p><em>Results of this approach:</em><br>
  This works a little better; at the very least, when you select a <code>mat-option</code>,  You can just strip the extra whitespace between the option you want, and the description text.</p>
  
  <p>However, this still does not work, because whenever you load up a model, the <code>mat-select</code> text <strong>does not run this text-sanitation code!</strong>  So, you wind up with the undesirable <code>mat-select</code> text as shown in the first pass.</p>
  
  <p><strong>Pass #3 - Okay, then why not bind to a list, and swap the list on select?</strong><br>
  Because our second pass was closer to what we wanted, we then figured that maybe what we can do is swap the lists entirely to get the desired behavior!  This called for some modified markup and component code.</p>
  
  <p><em>Markup:</em>  </p>
  
  <pre><code>&lt;mat-select name="SomePermissionDropdown"
              (click)="onOpenedSomePermissionOptions()"
              (selectionChange)="onPermissionChanged($event)"
              [(ngModel)]="permissionModel.somePermission"&gt;
    &lt;mat-option *ngFor="let option of somePermissionLevels"
                [(value)]="option.value"&gt;
      {{ option.displayText }}
    &lt;/mat-option&gt;
  &lt;/mat-select&gt;
  </code></pre>
  
  <p><em>Component Code:</em><br>
  Note - only the parts of the controller code relevant to the problem are shown.</p>
  
  <pre><code>@Component({ 
    selector: 'app-permission',
    templateUrls: './permission.component.html',
    styleUrls: ['./permission.component.scss']
  })
  export class PermissionComponent {
    somePermissionLevelsBasic: any[] = [
      { "value": 0, "displayText": "None" },
      { "value": 1, "displayText": "Make requests" },
      { "value": 2, "displayText": "View requests" },
    ];
  
    somePermissionLevelsVerbose: any[] = [
      { "value": 0, "displayText": 'None' },
      { "value": 1, "displayText": 'Make requests&lt;span class="permission-description"&gt;You can make requests, but you can\'t see anyone else\'s&lt;/span&gt;' },
      { "value": 2, "displayText": "View requests&lt;span class="permission-description"&gt;You can make requests and view requests created by other people&lt;/span&gt;" },
    ];
  
    somePermissionLevels: any[] = this.somePermissionLevelsBasic;
  
    onOpenedSomePermissionOptions() {
      this.somePermissionLevels = this.somePermissionLevelsVerbose;
    }
  
    onPermissionLevelChanged(event: any) {
      this.somePermissionLevels = this.somePermissionLevelsBasic;
    }
  }
  </code></pre>
  
  <p><em>Results of this approach:</em><br>
  Just as this was conceived of as the inverse of Pass #2, this has the inverse results of Pass #2.  When a model is loaded, the value appears correctly.  However, when you click the <code>mat-select</code> to view your options, you see a new form of aberrant text in each <code>mat-option</code>:</p>
  
  <pre><code>Make requests&lt;span class="permission-description"&gt;You can make requests, but you can\'t see anyone else\'s&lt;/span&gt;
  </code></pre>
  
  <p>The switching of lists doesn't cause the HTML and CSS of the option content to be evaluated, it appears.  Just as in Pass #1, I've also found no exposed means to manipulate this.</p>
  
  <p><strong>Question:</strong>
  With great exhaustion, I ask: how does one create a <code>mat-select</code> dropdown that has <code>mat-options</code> that describe what each <code>mat-option</code> does?  It appears A) that the Angular team took functionality away from us, and B) that Angular's <code>mat-select</code> simply isn't designed to accomodate any hackery our team has been able to conceive of to work around these limitations.</p>