Угловой 7, Реактивная форма медленного ответа, когда имеет большие данные - PullRequest
0 голосов
/ 05 февраля 2019

У меня очень сложные и большие данные, и мне нужно построить реактивную форму вокруг него в компоненте.

Я разработал форму.Но когда я что-то набираю в одном из полей input для редактирования заполненных данных, он очень медленно реагирует на обновление значения этого поля.

Я пытался использовать updateOn:'blur' и 'submit', но безуспешно.

Мой вопрос: как лучше обрабатывать форму с большими данными?

Обновление : Это мой StackBlitz .

Примечание : я создал очень минимальную версию моей фактической реализациии у меня есть проблемы с производительностью в Реактивной форме.

1 Ответ

0 голосов
/ 07 февраля 2019

Итак, после дня игры с вашим StackBlitz, вот и я.Я думаю, что это значительно повысит производительность.

Шаг 1: Создайте интерфейсы для вашей модели данных

Это значительно улучшит код и сделает его более читабельным.Это также сделало бы код более управляемым и простым в работе.Итак, мы идем со списком interface с для вашего конкретного сценария:

export interface Hotel {
  id: string;
  currencyId: string;
  hotelYearId: string;
  priceTaxTypeId: string;
  code: string;
  name: string;
  createBy: string;
  createDate: string;
  lastUpdateBy: string;
  lastUpdateDate: string;
  remark: string;
  internalRemark: string;
  roomTypes: RoomType[];
}

export interface RoomType {
  chk: boolean;
  roomTypeId: string;
  mealTypes: MealType[];
}

export interface MealType {
  chk: boolean;
  mealTypeId: string;
  marketGroups: MarketGroup[];
}

export interface MarketGroup {
  chk: boolean;
  markets: Market[];
  rateSegments: RateSegment[];
}

export interface Market {
  marketId: string;
}

export interface RateSegment {
  chk: boolean;
  rateSegmentId: string;
  hotelSeasons: HotelSeason[];
}

export interface HotelSeason {
  chk: boolean;
  hotelSeasonId: string;
  rates: Rate[];
}

export interface Rate {
  rateCodeId: string;
  cancellationPolicyId: string;
  dayFlag: string;
  singlePrice: string;
  doublePrice: string;
  xbedPrice: string;
  xbedChildPrice: string;
  bfPrice: string;
  bfChildPrice: string;
  unitMonth: string;
  unitDay: string;
  minStay: number;
}

Шаг 2: Измените способ создания формы

Способ созданияФорма очень шумная.Есть четкий способ сделать это.И поскольку вы уже создаете форму в службе, я предлагаю вам сохранить задачу создания формы для самой службы и освободить свой компонент от любых подобных задач.Таким образом, ваш сервис может быть реорганизован следующим образом:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { FormBuilder, Validators } from '@angular/forms';
import { map } from 'rxjs/operators';

import { Hotel, RoomType, MealType, MarketGroup, Market, RateSegment, HotelSeason, Rate } from './hotel.model';

@Injectable()
export class UtilService {

  constructor(
    private readonly fb: FormBuilder,
    private readonly http: HttpClient
  ) { }

  getHotelForm() {
    return this.getHotel().pipe(
      map((apiResponse: any) => this.fb.group({
        id: [apiResponse.id, Validators.required],
        currencyId: [apiResponse.currencyId, Validators.required],
        hotelYearId: [apiResponse.hotelYearId, Validators.required],
        priceTaxTypeId: [apiResponse.priceTaxTypeId, Validators.required],
        code: [apiResponse.code, Validators.required],
        name: [apiResponse.name, Validators.required],
        createBy: [apiResponse.createBy, Validators.required],
        createDate: [apiResponse.createDate, Validators.required],
        lastUpdateBy: [apiResponse.lastUpdateBy, Validators.required],
        lastUpdateDate: [apiResponse.lastUpdateDate, Validators.required],
        remark: [apiResponse.remark, Validators.required],
        internalRemark: [apiResponse.internalRemark, Validators.required],
        roomTypes: this.fb.array(apiResponse.roomTypes.map(roomType => this.generateRoomTypeForm(roomType)))
      }))
    );
  }

  private getHotel() {
    return this.http.get('/assets/hotel.json');
  }

  private generateRoomTypeForm(roomType: RoomType) {

    const roomTypeForm = this.fb.group({
      chk: [roomType.chk, Validators.required],
      roomTypeId: [roomType.roomTypeId, Validators.required],
      mealTypes: this.fb.array(roomType.mealTypes.map(mealType => this.generateMealTypeForm(mealType)))
    });

    return roomTypeForm;
  }

  private generateMealTypeForm(mealType: MealType) {

    const mealTypeForm = this.fb.group({
      chk: [mealType.chk, Validators.required],
      mealTypeId: [mealType.mealTypeId, Validators.required],
      marketGroups: this.fb.array(mealType.marketGroups.map(marketGroup => this.generateMarketGroupForm(marketGroup)))
    });

    return mealTypeForm;
  }

  private generateMarketGroupForm(marketGroup: MarketGroup) {

    const marketGroupForm = this.fb.group({
      chk: [marketGroup.chk, Validators.required],
      markets: this.fb.array(marketGroup.markets.map(market => this.generateMarketForm(market))),
      rateSegments: this.fb.array(marketGroup.rateSegments.map(rateSegment => this.generateRateSegmentForm(rateSegment))),
    });

    return marketGroupForm;
  }

  private generateMarketForm(market: Market) {
    return this.fb.group({
      marketId: [market.marketId, Validators.required]
    });
  }

  private generateRateSegmentForm(rateSegment: RateSegment) {
    const rateSegmentForm = this.fb.group({
      chk: [rateSegment.chk, Validators.required],
      rateSegmentId: [rateSegment.rateSegmentId, Validators.required],
      hotelSeasons: this.fb.array(rateSegment.hotelSeasons.map(hotelSeason => this.generateHotelSeasonForm(hotelSeason)))
    });

    return rateSegmentForm;
  }

  private generateHotelSeasonForm(hotelSeason: HotelSeason) {

    const hotelSeasonForm = this.fb.group({
      chk: [hotelSeason.chk, Validators.required],
      hotelSeasonId: [hotelSeason.hotelSeasonId, Validators.required],
      rates: this.fb.array(hotelSeason.rates.map(rate => this.generateRateForm(rate)))
    });
    return hotelSeasonForm;
  }

  private generateRateForm(rate: Rate) {
    return this.fb.group({
      rateCodeId: [rate.rateCodeId, Validators.required],
      cancellationPolicyId: [rate.cancellationPolicyId, Validators.required],
      dayFlag: [rate.dayFlag, Validators.required],
      singlePrice: [rate.singlePrice, Validators.required],
      doublePrice: [rate.doublePrice, Validators.required],
      xbedPrice: [rate.xbedPrice, Validators.required],
      xbedChildPrice: [rate.xbedChildPrice, Validators.required],
      bfPrice: [rate.bfPrice, Validators.required],
      bfChildPrice: [rate.bfChildPrice, Validators.required],
      unitMonth: [rate.unitMonth, Validators.required],
      unitDay: [rate.unitDay, Validators.required],
      minStay: [rate.minStay, Validators.required]
    });
  }

}

Шаг 3. Воспользуйтесь вышеуказанным сервисом:

Сделайте это, чтобы получить форму и избавиться от methods, который вернется квы FormArray s в вашем шаблоне.Это сделало бы ваш Компонент очень чистым, ясным и лаконичным.

import { Component, ChangeDetectionStrategy } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { Observable } from 'rxjs';

import { UtilService } from '../app/util.service';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  changeDetection: ChangeDetectionStrategy.OnPush
})

export class AppComponent {

  form$: Observable<FormGroup> = this.util.getHotelForm();

  constructor(private readonly util: UtilService) {
  }

}

Шаг 4: Рефакторинг вашего шаблона:

И этот САМЫЙ ВАЖНЫЙ . НИКОГДА вызовите методы получения или методы в глубоко вложенных формах, чтобы получить FormArray s.Вернее, в обычных формах или в синтаксисе привязки данных в целом.Потому что они будут вызываться в каждом цикле обнаружения изменений и будут снижать производительность вашего приложения.

Пожалуйста, обратитесь к этой молниеносной речи Таннера Эдвардса из ng-conf 2018 чтобы узнать больше об этом.

Итак, вы можете реорганизовать свой шаблон компонента следующим образом:

<code><form 
  *ngIf="form$ | async as form" 
  [formGroup]="form">
    <div 
    formArrayName="roomTypes">
        <div 
      *ngFor="let roomType of form.controls['roomTypes'].controls; let index = index" 
      [formGroupName]="index">
            {{index}}
            <div 
        formArrayName="mealTypes">
                <div 
          *ngFor="let mealType of roomType.controls['mealTypes'].controls; let mealtypeIndex = index"
          [formGroupName]="mealtypeIndex">
                    mealtype {{mealtypeIndex}}
                    <div 
            formArrayName="marketGroups">
                        <div 
              *ngFor="let marketGroup of mealType.controls['marketGroups'].controls; let marketGroupIndex = index" 
              [formGroupName]="marketGroupIndex">
                            marketGroupIndex {{marketGroupIndex}}
                            <div formArrayName="rateSegments">
                                <div 
                  *ngFor="let rateSegment of marketGroup.controls['rateSegments'].controls; let rateSegmentIndex = index"
                  [formGroupName]="rateSegmentIndex">
                                    rateSegmentIndex {{rateSegmentIndex}}
                                    <div formArrayName="hotelSeasons">
                                        <div 
                      class="fifth_border" 
                      *ngFor="let hotelseason of rateSegment.controls['hotelSeasons'].controls; let hotelseasonIndex = index"
                      [formGroupName]="hotelseasonIndex">
                                            hotelseasonIndex {{hotelseasonIndex}}
                                            <div formArrayName="rates">
                                                <div 
                          *ngFor="let rate of hotelseason.controls['rates'].controls; let rateIndex = index"
                          [formGroupName]="rateIndex">
                          <div style="display:flex;flex-flow;row">
                            <div>
                              <p>SGL</p>
                              <input class="input text_right" type="text" formControlName="singlePrice">
                            </div>
                            <div>
                              <p>DLB/TWN</p>
                              <input class="input text_right" type="text"  formControlName="doublePrice">
                            </div>
                            <div>
                              <p>EX-Adult</p>
                              <input class="input text_right" type="text"  formControlName="xbedPrice" >
                            </div>
                            <div>
                              <p>EX-Child</p>
                              <input class="input text_right" type="text"  formControlName="xbedChildPrice">
                            </div>
                            <div>
                              <p>Adult BF</p>
                              <input class="input text_right" type="text"  formControlName="bfPrice">
                            </div>
                            <div>
                              <p>Child BF</p>
                              <input class="input text_right" type="text"  formControlName="bfChildPrice">
                            </div>
                          </div>
                        </div>
                      </div>
                    </div>
                  </div>
                </div>
              </div>
            </div> 
          </div>
        </div>
      </div>
    </div>
  </div>
  <!-- <pre>{{form.value | json}}
->

Шаг 5: Не останавливайтесь здесь

Это не конец.Это только начало.Вы также можете абстрагировать дочернюю форму (marketGroup FormGroup внутри marketGroups FormArray) в отдельный компонент.И тогда вы можете установить его changeDetectionStrategy на OnPush.Это даст вам еще лучшую производительность.

Вот StackBliz , к которому вы можете обратиться, чтобы взглянуть на это решение.

Выполнение всего этого значительно улучшит производительность формы.

Надеюсь, это поможет.Я постараюсь обновить этот ответ, если найду что-нибудь еще, чтобы улучшить производительность сверх этого предела.


Вот Рабочий пример StackBlitz для вашей ссылки.


Вот Подробная средняя статья об этом, которую я написал для AngularInDepth .


Разница в производительности

Я только что провел аудит производительности вашей реализации, а также мой для того же набора шагов, выполненных в приложении.

Вот сводка с вашей реализацией:

enter image description here

А вот сводка с измененной реализацией:

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...