首页 > 解决方案 > Angular6 Form only responds after periodic zone.js change detection

问题描述

I have a very strange case: After setting up a component containing a form, interacting with the form is incredibly slow. After a click on a dropdown, the form reacts only when the zone.js timeout occurs and the periodic change detection kicks in. Any idea why this could be the case? Why would a component/form be outside of the zone.js change detection? I don't have any errors.

The only debugging input I have is, that on performance profiling in chrome devtools, I get the tap event and then 5-12seconds later, zone.js triggers the UI animation of showing the dropdown options.

In the Chrome DevTools Performance Profiler, this looks like this: Overall Profiling

I tap the dropdown around 2 seconds after profiling: Tap happens

And then 10 seconds later, zone.js, does a periodic update which triggers the dropdown: zone.js change detection runs and dropdown is triggered

Between, nothing happens.

I'm using NgRx and the switch to the component with the form happens in an @Effect, where I call the router.

The Effect looks like this: (It wasn't working with RxJS5 either, so it shouldn't have anything to do with the migration)

  @Effect()
  placesDetails$ = this.actions$
    .ofType<PlaceSelectedAction>(PLACE_SELECTED_ACTION)
    .pipe(
      switchMap((action: PlaceSelectedAction) =>
        this.placesService.loadPlacesDetails(action.payload)
      ),
      map(data => new PlaceDetailsLoadedAction(data)),
      tap(_ => this.router.navigate(["/place-details"]))
    );

The component itself looks like this:

import { Component } from "@angular/core";
import { Store } from "@ngrx/store";
import { ApplicationState } from "../store/application-state";
import { Router } from "@angular/router";
import { Card } from "../../../../shared/model/card";

@Component({
  selector: "app-place-details",
  templateUrl: "./place-details.component.html",
  styleUrls: ["./place-details.component.scss"]
})
export class PlaceDetailsComponent {
  card: Card;

  constructor(private store: Store<ApplicationState>, private router: Router) {
    this.store.subscribe(state => (this.card = state.cardDataState.card));
  }

  travelTypeLocation = [
    { value: "city", viewValue: "City" },
    { value: "beach", viewValue: "Beach" },
    { value: "mountains", viewValue: "Mountains" },
    { value: "countryside", viewValue: "Countryside" }
  ];

  travelTypeActivity = [
    { value: "relax", viewValue: "Relax" },
    { value: "sports", viewValue: "Sports" },
    { value: "culture", viewValue: "Culture" },
    { value: "party", viewValue: "Party" }
  ];

  travelTypeCompanions = [
    { value: "family", viewValue: "Family" },
    { value: "partner", viewValue: "Partner" },
    { value: "single", viewValue: "Single" },
    { value: "friends", viewValue: "Friends" },
    { value: "colleagues", viewValue: "Colleagues" }
  ];

  checkPlaceDetails() {
    //this.store.dispatch(new PlaceDetailsSubmitAction());
  }

  goBack() {
    this.router.navigate(["/search-places"]);
  }
}

And this is the HTML:

<div class="container" fxLayout.xs="column">
  <h3>Fill out Place Details</h3>

  <form>

    <mat-form-field class="full-width">
      <input
        matInput
        placeholder="Title"
        type="text"
        required
        name="title"
        [(ngModel)]="card.title">
      <mat-error *ngIf="card.title">{{ card.title }}</mat-error>
    </mat-form-field>

    <mat-form-field class="full-width">
      <input
        matInput
        placeholder="Description"
        type="text"
        name="description"
        required
        [(ngModel)]="card.description"
        />
    </mat-form-field>

    <mat-form-field class="full-width">
      <mat-select
        placeholder="Travel Type Location"
        name="travelTypeLocation"
        required
        [(ngModel)]="card.travelTypeLocation"
      >
        <mat-option *ngFor="let type of travelTypeLocation" [value]="type.value">
          {{ type.viewValue }}
        </mat-option>
      </mat-select>
    </mat-form-field>

    <mat-form-field class="full-width">
      <input
        matInput
        placeholder="Travel Dimension Location (e.g. surfing, biking, museum, theater)"
        type="text"
        name="travelDimensionLocation"
        required
        [(ngModel)]="card.travelDimensionLocation"
      />
    </mat-form-field>

    <mat-form-field class="full-width">
      <mat-select
        placeholder="Travel Type Activity"
        name="travelTypeActivity"
        required
        [(ngModel)]="card.travelTypeActivity"
      >
        <mat-option *ngFor="let type of travelTypeActivity" [value]="type.value">
          {{ type.viewValue }}
        </mat-option>
      </mat-select>
    </mat-form-field>

    <mat-form-field class="full-width">
      <input
        matInput
        placeholder="Travel Dimension Activity (e.g. modern city, historic city, hills, high mountains)"
        type="text"
        name="travelDimensionActivity"
        required
        [(ngModel)]="card.travelDimensionActivity"
      />
    </mat-form-field>

    <mat-form-field class="full-width">
      <mat-select
        placeholder="Travel Companions"
        name="travelTypeCompanions"
        required
        [(ngModel)]="card.travelTypeCompanions"
      >
        <mat-option *ngFor="let type of travelTypeCompanions" [value]="type.value">
          {{ type.viewValue }}
        </mat-option>
      </mat-select>
    </mat-form-field>

    <mat-form-field class="full-width">
      <input
        matInput
        placeholder="Duration"
        type="text"
        required
        name="duration"
        [(ngModel)]="card.averageDuration"
      />
    </mat-form-field>

    <mat-form-field class="full-width">
      <input
        matInput
        required
        placeholder="Cost (€)"
        type="number"
        name="cost"
        [(ngModel)]="card.cost"
      />
    </mat-form-field>

    <button mat-raised-button color="primary" (click)="checkPlaceDetails()">Add Card</button>
    <button mat-raised-button color="secondary" (click)="goBack()">Go Back</button>

  </form>
</div>

Please let me know what could be of importance? I'm lost.

Thanks!

标签: javascriptangularformszonejs

解决方案


这个很难弄清楚。但显然 zone.js 和 RxJS 存在错误。在包含它之后import 'zone.js/dist/zone-patch-rxjs';polyfills它现在可以按预期工作,在表单交互后没有延迟。


推荐阅读