title: Why is Angular Form very slow within MatDialog component?
body: <p>I have an Angular form in a Material Dialog component.  There is data being two-way binded and when tabbing through inputs or typing in inputs results in the screen locking up for a few seconds between keydown's .   All data is passing properly but is painfully slow while trying to use the form.  </p>
  
  <p>I've tried refactoring the form to use  for the inputs to use a "Material form" but still has the same slowdown performance.   </p>
  
  <p>Here's a screenshot of performance tracker in chrome: 
  <a href="https://i.stack.imgur.com/s9oeI.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/s9oeI.png" alt="Slow down performance over 10 seconds."></a></p>
  
  <p>Is there something wrong with my configuration?  Or is this a possible regression in latest Angular 8 animation / CDK packages?  Here are my Angular package dependencies: </p>
  
  <pre><code>dependencies": {
      "@angular/animations": "^8.2.13",
      "@angular/cdk": "^8.2.3",
      "@angular/common": "~8.2.13",
      "@angular/compiler": "~8.2.13",
      "@angular/core": "~8.2.13",
      "@angular/forms": "~8.2.13",
      "@angular/material": "^8.2.3",
      "@angular/platform-browser": "~8.2.13",
      "@angular/platform-browser-dynamic": "~8.2.13",
      "@angular/router": "~8.2.13",
  }
  </code></pre>
  
  <p>Here is the component method that calls the dialog: </p>
  
  <pre><code>public editRow(tablerow: IRule): void {
  const dialogRef = this.dialog.open(EditDialogComponent, {
    width: '100%',
    height: '85%',
    data: tablerow
  });
  
  this.subscriptions.push(
    dialogRef.afterClosed().subscribe(updatedRule =&gt; {
      if (updatedRule !== undefined) {
  
        this.rules = this.rules.map(rule =&gt; rule.Id === updatedRule.Id ? updatedRule : rule);
  
        this.subscriptions.push(this.dataService.updateRule(updatedRule).subscribe(
          response =&gt; {
            this.snackBar.openFromComponent(SuccessComponent, {
              duration: 3000,
              data: `Rule added`
            });
          }, error =&gt; {
            this.snackBar.openFromComponent(ErrorComponent, {
              duration: 10000,
              data: 'Internal Server Error'
            });
            }
          ));
        }
      })
    );
  }
  </code></pre>
  
  <p>The mat dialog template containing the form: </p>
  
  <pre><code>&lt;mat-dialog-content&gt;
  &lt;i id="close-icon" class="material-icons md-24" aria-label="close"
  [mat-dialog-close]&gt;close&lt;/i&gt;
  &lt;div class="brand-panel-container"&gt;
  &lt;div class="brand-panel"&gt;
    &lt;div class="brand-panel-header"&gt;
      &lt;div class="brand-title"&gt;
        &lt;h4 mat-dialog-title&gt;Rule: {{ data.Id }}&lt;/h4&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;form #ruleForm="ngForm"&gt;
      &lt;div class="row"&gt;
        &lt;div class="col-md-6"&gt;
          &lt;div class="form-group"&gt;
            &lt;label for="name"&gt;Shop Type:&lt;span class="asterisk"&gt;*&lt;/span&gt;&lt;/label&gt;
            &lt;select
              [(ngModel)]="data.Type.Text"
              value="{{ data.Type.Text }}"
              name="type"
              type="text"
              class="form-control"
              id="type"
              required&gt;
              &lt;option *ngFor="let opt of shopTypeOpts; trackBy: indentify" value="{{opt.Text}}"&gt;{{opt.Text}}&lt;/option&gt;
            &lt;/select&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class="col-md-6"&gt;
          &lt;div class="form-group"&gt;
            &lt;label for="name"&gt;Origin:&lt;span class="asterisk"&gt;*&lt;/span&gt;&lt;/label&gt;
            &lt;input
              [(ngModel)]="data.Origin"
              value="{{ data.Origin }}"
              name="origin"
              type="text"
              class="form-control"
              id="origin"
              required&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
  
      &lt;div class="row"&gt;
        &lt;div class="col-md-6"&gt;
          &lt;div class="form-group"&gt;
            &lt;label for="name"&gt;Destination:&lt;span class="asterisk"&gt;*&lt;/span&gt;&lt;/label&gt;
            &lt;input
              [(ngModel)]="data.Destination"
              value="{{ data.Destination }}"
              name="destination"
              type="text"
              class="form-control"
              id="destination"
              required&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class="col-md-6"&gt;
          &lt;div class="form-group"&gt;
            &lt;label for="name"&gt;Fare:&lt;span class="asterisk"&gt;*&lt;/span&gt;&lt;/label&gt;
            &lt;input
              [(ngModel)]="data.Fare.Text"
              value="{{ data.Fare.Text }}"
              name="fare"
              type="text"
              class="form-control"
              id="fare"
              required&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
  
      &lt;div class="row"&gt;
        &lt;div class="col-md-6"&gt;
          &lt;div class="form-group"&gt;
            &lt;label for="name"&gt;Government:&lt;span class="asterisk"&gt;*&lt;/span&gt;&lt;/label&gt;
            &lt;select
              [(ngModel)]="data.Government.Text"
              value="{{ data.Government.Text }}"
              name="government"
              type="text"
              class="form-control"
              id="government"
              required&gt;
              &lt;option *ngFor="let opt of governmentTypeOpts; trackBy: indentify"
                value="{{opt.Text}}"&gt;{{opt.Text}}&lt;/option&gt;
            &lt;/select&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class="col-md-6"&gt;
          &lt;div class="form-group"&gt;
            &lt;label for="name"&gt;Special Pricing:&lt;span class="asterisk"&gt;*&lt;/span&gt;&lt;/label&gt;
            &lt;select
              [(ngModel)]="data.SpecialPricing.Text"
              value="{{ data.SpecialPricing.Text }}"
              name="specialPricing"
              type="text"
              class="form-control"
              id="specialPricing"
              required&gt;
              &lt;option *ngFor="let opt of specialPricingTypeOpts; trackBy: indentify"
                value="{{opt.Text}}"&gt;{{opt.Text}}&lt;/option&gt;
            &lt;/select&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
  
      &lt;div class="row"&gt;
        &lt;div class="col-md-6"&gt;
          &lt;div class="form-group"&gt;
            &lt;label for="name"&gt;Upgrade:&lt;span class="asterisk"&gt;*&lt;/span&gt;&lt;/label&gt;
            &lt;select
              [(ngModel)]="data.Upgrade.Text"
              value="{{ data.Upgrade.Text }}"
              name="upgrade"
              type="text"
              class="form-control"
              id="upgrade"
              required&gt;
              &lt;option *ngFor="let opt of upgradeTypeOpts; trackBy: indentify"
                value="{{opt.Text}}"&gt;{{opt.Text}}&lt;/option&gt;
            &lt;/select&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class="col-md-6"&gt;
          &lt;div class="form-group"&gt;
            &lt;label for="name"&gt;Cabin Count:&lt;span class="asterisk"&gt;*&lt;/span&gt;&lt;/label&gt;
            &lt;input
              [(ngModel)]="data.CabinCount"
              value="{{ data.CabinCount }}"
              name="cabinCount"
              type="text"
              class="form-control"
              id="cabinCount"
              required&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
  
      &lt;div class="row"&gt;
        &lt;div class="col-md-6"&gt;
          &lt;div class="form-group"&gt;
            &lt;label for="name"&gt;Columns Count:&lt;span class="asterisk"&gt;*&lt;/span&gt;&lt;/label&gt;
            &lt;input
              [(ngModel)]="data.ColumnsCount"
              value="{{ data.ColumnsCount }}"
              name="columnsCount"
              type="text"
              class="form-control"
              id="columnsCount"
              required&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class="col-md-6"&gt;
          &lt;div class="form-group"&gt;
            &lt;label for="name"&gt;Lang Code:&lt;span class="asterisk"&gt;*&lt;/span&gt;&lt;/label&gt;
            &lt;input
              [(ngModel)]="data.LangCode"
              value="{{ data.LangCode }}"
              name="langCode"
              type="text"
              class="form-control"
              id="langCode"
              required&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
  
      &lt;div class="row"&gt;
        &lt;div class="col-md-6"&gt;
          &lt;div class="form-group"&gt;
            &lt;label for="name"&gt;Fare Wheel Search?:&lt;span class="asterisk"&gt;*&lt;/span&gt;&lt;/label&gt;
            &lt;input
              [(ngModel)]="data.IsFareWheelSearch"
              value="{{ data.IsFareWheelSearch }}"
              name="isFareWheelSearch"
              type="text"
              class="form-control"
              id="isFareWheelSearch"
              required&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class="col-md-6"&gt;
          &lt;div class="form-group"&gt;
            &lt;label for="name"&gt;Markets:&lt;span class="asterisk"&gt;*&lt;/span&gt;&lt;/label&gt;
            &lt;select
              [(ngModel)]="data.Markets.Text"
              value="{{ data.Markets.Text }}"
              name="markets"
              type="text"
              class="form-control"
              id="markets"
              required&gt;
              &lt;option *ngFor="let opt of marketTypeOpts; trackBy: indentify" value="{{opt.Text}}"&gt;{{opt.Text}}&lt;/option&gt;
            &lt;/select&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
  
      &lt;div class="row"&gt;
        &lt;div class="col-md-6"&gt;
          &lt;div class="form-group"&gt;
            &lt;label for="name"&gt;POS:&lt;span class="asterisk"&gt;*&lt;/span&gt;&lt;/label&gt;
            &lt;input
              [(ngModel)]="data.POS"
              value="{{ data.POS }}"
              name="pos"
              type="text"
              class="form-control"
              id="pos"
              required&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class="col-md-6"&gt;
          &lt;div class="form-group"&gt;
            &lt;label for="name"&gt;Columns:&lt;span class="asterisk"&gt;*&lt;/span&gt;&lt;/label&gt;
            &lt;input
              [(ngModel)]="data.Columns"
              value="{{ data.Columns }}"
              name="columns"
              type="text"
              class="form-control"
              id="columns"
              required&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
  
      &lt;div mat-dialog-actions&gt;
        &lt;span *ngIf="!ruleForm.valid" class="invalid-msg"&gt;&lt;span
            class="asterisk"&gt;*&lt;/span&gt;All fields must be filled in to save
          changes.&lt;/span&gt;
        &lt;button mat-button class="brand-default-button"
          [mat-dialog-close]&gt;Cancel&lt;/button&gt;
        &lt;button mat-button class="brand-confirm-button" type="submit"
          [disabled]="!ruleForm.valid" [mat-dialog-close]="data.Id"
          (click)="onSaveData(ruleForm.value)"&gt;Save Changes&lt;/button&gt;
      &lt;/div&gt;
    &lt;/form&gt;
  &lt;/div&gt;
  </code></pre>
  
  <p>
  </p>
  
  <p>The dialog component file: </p>
  
  <pre><code>import { Component, Inject } from '@angular/core';
  import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
  import { IRule } from '../../../models/rule.interface';
  import { OptionsService } from 'src/app/shared/services/options.service';
  import { IDropdownOption } from 'src/models/dropdown-option.interface';
  
  @Component({
    selector: 'app-edit-dialog',
    templateUrl: './edit-dialog.component.html',
    styleUrls: ['./edit-dialog.component.scss']
  })
  export class EditDialogComponent {
  
    public shopTypeOpts: IDropdownOption[] = [];
    public governmentTypeOpts: IDropdownOption[] = [];
    public specialPricingTypeOpts: IDropdownOption[] = [];
    public fareTypeOpts: IDropdownOption[] = [];
    public upgradeTypeOpts: IDropdownOption[] = [];
    public marketTypeOpts: IDropdownOption[] = [];
  
    constructor(
      public dialogRef: MatDialogRef&lt;EditDialogComponent&gt;,
      public optionsService: OptionsService,
      @Inject(MAT_DIALOG_DATA) public data: IRule) {
      this.shopTypeOpts = this.optionsService.shopTypeOptions;
      this.governmentTypeOpts = this.optionsService.governmentTypeOptions;
      this.specialPricingTypeOpts = this.optionsService.specialPricingTypeOptions;
      this.fareTypeOpts = this.optionsService.fareTypeOptions;
      this.upgradeTypeOpts = this.optionsService.upgradeTypeOptions;
      this.marketTypeOpts = this.optionsService.marketTypeOptions;
    }
  
    public onSaveData(updatedRule: IRule): void {
      this.dialogRef.close(updatedRule);
    }
  
    public indentify(index, item) {
      return item.Text;
    }
  
  }
  </code></pre>
  
  <p>IDropdownOption interface: </p>
  
  <pre><code>export interface IDropdownOption {
    Text: string;
    Value: number;
  }
  </code></pre>
  
  <p><strong>*EDITED to include trackBy function &amp; IDropdownOption interface to see unique identifier. *</strong></p>
  
  <p>The slow down seems to be because of the dropdown options being looped over repeatedly... Maybe changeDetection strategy needs to be changed?  </p>