如何创建 Material Design Select 下拉菜单,其选项内容取决于选项选择?

How to create a Material Design Select dropdown with option content that is dependent on option selection?

背景:
对于我正在从事的项目,我的团队有一个权限系统,为了我们的最终用户,我们想描述每个级别的权限需要什么。

我所在的团队在 AngularJS Material 设计中的做法是,我们只是在每个 md-option 中包含一些额外的 HTML ,如果那个特定的 md-option 被 selected,它被设计为隐藏。我们后来发现这在 Angular Material 设计中不起作用。

我们的尝试:
首先,是最初的实现,基于我们团队在 AngularJS 时代使用的东西:

通过 #1 - HTML/CSS 在垫选项中(不工作)
标记:

<mat-select name="SomePermissionDropdown"
            [(ngModel)]="permissionModel.somePermission">
  <!-- 'None' has no description by design. -->
  <mat-option class="permission-option" value="0">
    None
  </mat-option>
  <mat-option class="permission-option" value="1">
    Make requests
    <span class="permission-description">You can make requests, but you can't see anyone else's</span>
  </mat-option>
  <mat-option class="permission-option" value="2">
    View requests
    <span class="permission-description">You can make requests and view requests created by other people</span>
  </mat-option>
</mat-select>

SCSS:

.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;
}

这种方法的结果: 每当加载记录或 selected 值时,而不是按预期隐藏 permission-description,在下拉列表中看到的是如下文字:

Make requests  You can make requests, but you can't see anyone else's

基本上,当某人 select 在 Angular Material Design 的 mat-select 中输入 mat-option 时,似乎文本已被采用,所有 HTML 都是剥离出来,净化后的 HTML 是放置在实际 mat-select 文本标签中的内容。我一直无法找到任何方法来覆盖此行为。

为什么这很糟糕: Angular 团队确实取消了 AngularJS Material 设计中存在的功能。

第 2 步 - 好吧,让我们临时删除描述文本!
我们用 (selectionChange) 事件修改了第一遍的 mat-select

<mat-select name="SomePermissionDropdown"
            (selectionChange)="onPermissionChanged($event)"
            ...>

其中 onPermissionChanged 具有以下组件代码:

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;
}  

这种方法的结果:
这样效果好一点;至少,当你 select a mat-option 时,你可以去掉你想要的选项和描述文本之间的额外空白。

但是,这仍然不起作用,因为每当您加载模型时,mat-select 文本 不会 运行 这个文本卫生代码! 因此,您最终得到了不受欢迎的 mat-select 文本,如第一遍所示。

通过 #3 - 好的,那为什么不绑定到一个列表,然后在 select 上交换列表?
因为我们的第二遍更接近我们想要的,所以我们认为也许我们可以做的是完全交换列表以获得所需的行为!这需要一些修改后的标记和组件代码。

标记:

<mat-select name="SomePermissionDropdown"
            (click)="onOpenedSomePermissionOptions()"
            (selectionChange)="onPermissionChanged($event)"
            [(ngModel)]="permissionModel.somePermission">
  <mat-option *ngFor="let option of somePermissionLevels"
              [(value)]="option.value">
    {{ option.displayText }}
  </mat-option>
</mat-select>

组件代码:
注意 - 仅显示与问题相关的控制器代码部分。

@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<span class="permission-description">You can make requests, but you can\'t see anyone else\'s</span>' },
    { "value": 2, "displayText": "View requests<span class="permission-description">You can make requests and view requests created by other people</span>" },
  ];

  somePermissionLevels: any[] = this.somePermissionLevelsBasic;

  onOpenedSomePermissionOptions() {
    this.somePermissionLevels = this.somePermissionLevelsVerbose;
  }

  onPermissionLevelChanged(event: any) {
    this.somePermissionLevels = this.somePermissionLevelsBasic;
  }
}

这种方法的结果:
正如这被认为是 Pass #2 的逆运算一样,这具有 Pass #2 的逆结果。加载模型时,该值会正确显示。但是,当您单击 mat-select 查看您的选项时,您会在每个 mat-option:

中看到一种新形式的异常文本
Make requests<span class="permission-description">You can make requests, but you can\'t see anyone else\'s</span>

列表的切换不会导致对选项内容的 HTML 和 CSS 进行评估,它出现了。就像第 1 关一样,我也没有发现任何操纵它的方法。

问题: 我精疲力尽地问:如何创建一个 mat-select 下拉列表,其中包含 mat-options 描述每个 mat-option 的作用?看起来 A) Angular 团队从我们这里拿走了功能,并且 B) Angular 的 mat-select 根本不是为了适应我们团队能够设想的任何黑客技术而设计的来解决这些限制。

Angular 2 通过模板引用变量使这变得更容易(并且更安全,正如您在 pass#3 中看到的那样)。

<mat-option value="1" #opt>
    Make requests
    <span *ngIf="!opt.selected">
        You can make requests, but you can't see anyone else's
    </span>
</mat-option>