Angular: Реактивная ошибка формы с полем - PullRequest
0 голосов
/ 14 февраля 2020

У меня есть форма, позволяющая мне создать запрос на разрешение, заполнив различные поля.

Чтобы отобразить разрешение, я использую метод patchValue для обновления информации о форме.

Моя проблема заключается в том, что когда я не добавляю вложение, все поля остаются пустыми, и наоборот, если я добавляю все поля заполнены их значениями. Я не знаю, что вызывает такое поведение, тем более что при проверке сетевых запросов информация загружается. У кого-нибудь есть повод для отладки? Вот мой код:

/**
* Attachment & FileAttachment Model
**/
export class WorkPermitFileAttachment {
  public ID: number;
  public FileAttachment: FileAttachment = new FileAttachment();
  public Tags = '';
  constructor(partial?: Partial<WorkPermitFileAttachment>) {
    Object.assign(this, partial);
    this.FileAttachment.createFileObject();
  }
  public static createFromFlat(partial?: Partial<any>) {
    const myWorkPermitFileAttachment = new WorkPermitFileAttachment();
    if (partial) {
      myWorkPermitFileAttachment.Tags = partial.Tags;
      myWorkPermitFileAttachment.ID = partial.ID;
      delete partial.Tags;
      Object.assign(myWorkPermitFileAttachment.FileAttachment, partial);
      myWorkPermitFileAttachment.FileAttachment.createFileObject();
    }
    return myWorkPermitFileAttachment;
  }
  public static flattenToPOJO(partial?: Partial<WorkPermitFileAttachment>) {
    const plainObject = {
      ...partial,
      ...partial.FileAttachment,
    };

    delete plainObject.FileAttachment;
    delete plainObject.FileObject;
    return plainObject;
  }
}

export class FileAttachment {
  public ID: number;
  public Data: string;
  public Name: string;
  public Size: number;
  public Type: string;
  public FileObject: File = null;
  constructor(partial?: Partial<FileAttachment>) {
    Object.assign(this, partial);
    this.createFileObject();
  }
  public static createFromFile(file: File): Observable<FileAttachment> {
    return FileAttachment.fileToBase64(file).pipe(
        map(base64File => {
          return new FileAttachment({
            Data: FileAttachment.base64ToK2File(file.name, base64File),
            Name: file.name,
            Size: file.size,
            Type: file.type,
          });
        })
    );
  }
  protected static base64ToK2File(fileName, base64File) {
    const [_, fileEncoded] = base64File.split('base64,');
    return `<file><name>${fileName}</name><content>${fileEncoded}</content></file>`;
  }
  public static fileToBase64(file: File) {
    return from(new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.readAsDataURL(file);
      reader.onload = () => resolve(reader.result);
      reader.onerror = error => reject(error);
    }));
  }
  public static b64toBlob(base64, contentType = '', sliceSize = 512): Blob {
    const [all, base64String] = base64.match(/<content>(.*)<\/content>/);
    const byteCharacters = atob(base64String);
    const byteArrays = [];
    for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
      const slice = byteCharacters.slice(offset, offset + sliceSize);
      const byteNumbers = new Array(slice.length);
      for (let i = 0; i < slice.length; i++) {
        byteNumbers[i] = slice.charCodeAt(i);
      }
      const byteArray = new Uint8Array(byteNumbers);
      byteArrays.push(byteArray);
    }
    return new Blob(byteArrays, { type: contentType });
  }
  public createFileObject() {
    if (this.Data && this.Name) {
      this.FileObject = new File([this.toBlob()], this.Name);
    }
  }
  public getDataBase64() {
    const [all, base64String] = this.Data.match(/<content>(.*)<\/content>/);
    return `data:${this.Type};base64,${base64String}`;
  }
  public getFileAttachmentLink() {
    return this.getDataBase64();
  }
  public getImageSrc() {
    return this.getDataBase64();
  }
  public isImage() {
    return [
      'image/jpeg',
      'image/png',
      'image/gif',
      'image/svg+xml',
    ].includes(this.Type);
  }
  private toBlob(): Blob {
    return FileAttachment.b64toBlob(this.Data, this.Type);
  }
}
/**
* Request Model
**/
export class WorkPermitRequest {
  ID: number = null;
  RelatedWorkPermitRequestID: number = null;
  Reference: string = null;
  IsUrgent: Boolean = false;
  IsMOEApprobationRequested: Boolean = false;
  AuthorUserName: string = null;
  AuthorUserDisplayName: string = null;
  IsTrackConsigned: Boolean = false;
  IsEquipementConsigned: Boolean = false;
  EquipmentToConsign: string = null;
  IsEquipementShutDown: Boolean = false;
  EquipmentToShutDown: string = null;
  IsCoWorkingPossible: Boolean = true;
  IsTunnelPathUsed: Boolean = false;
  IsTrainNeeded: Boolean = false;
  IsEscortRequested: Boolean = false;
  IsZtconKeptPowered: Boolean = false;
  IsTrackPlateformAccessible: Boolean = false;
  IsTraficFreezed: Boolean = false;
  FreezedTraficReason: string = null;
  WorkDescriptionArea: string = null;
  @Association({
    mapping: 'OneToMany', mappedBy: 'WorkPermitRequestID', service: WorkPermitFileAttachmentService
  })
  FileAttachments: WorkPermitFileAttachment[] = [];
  InterventionStartDate: Date = new Date();
  InterventionEndDate: Date = new Date();
  IsOutOfDock: Boolean = false;
  IsWithinTheDockLimits: Boolean = false;
  IsWorkOnTheTrack: Boolean = false;
  IsEquipementConsignationRequired: Boolean = false;
  IsPreventionPlanNeeded: Boolean = false;
  ComplementaryMesure: string = null;
  PreventionPlanRef: string = null;
  WorkRepresentativeName: string = null;
  WorkRepresentativePhoneNumber: string = null;
  WorkRepresentativeMail: string = null;
  WorkRepresentativeCompanyID: number = null;
  QMRSComment: string = null;
  MaintenanceComment: string = null;
  ExploitationComment: string = null;
  OtherComment: string = null;
  LastReworkComment: string = null;
  PlannedWorkComment: string = null;
  Step = 'CREATION';
  Status: string = null;
  CreatedByUserName: string = null;
  CreatedByDisplayName: string = null;
  CreatedAt: Date = null;
  ModifiedByUserName: string = null;
  ModifiedByDisplayName: string = null;
  ModifiedAt: Date = null;
  constructor(partials?: Partial<any> | null) {
    if (partials) {
      Object.keys(partials).forEach((key) => (partials[key] == null) && delete partials[key]); // remove null property
    }
    Object.assign(this, partials);
  }
  public isExtendable() {
    return this.getDaysBetweenToday(this.InterventionEndDate) <= MAX_EXTEND_DELAY;
  }
  private toDate(property: string): Date {
    return new Date(property);
  }
  private getDaysBetweenToday(date: Date) {
    date = new Date(date);
    const MS_IN_DAY = 1000 * 60 * 60 * 24;
    // Define the work permit request end date
    const end = new Date(
      date.getFullYear(),
      date.getMonth(),
      date.getDate(),
    );
    // Define the boundary date
    const now = new Date();
    const boundary = new Date(
      now.getFullYear(),
      now.getMonth(),
      now.getDate(),
    );
    return (boundary.getTime() - end.getTime()) / MS_IN_DAY;
  }
}
/**
* Request Component
**/
export class WorkPermitRequestComponent implements OnInit, OnDestroy {
    public pickObjectProperties(object, properties) {
        const newObject = {};
        properties.forEach(property => newObject[property] = object[property]);
        return newObject;
    }

    public getGlobalForm(workPermitRequest, isInitForm) {
        const mapping = this.getMapping();
        return Object.keys(mapping).reduce((object, key) => {
            if (Array.isArray(mapping[key])) {
                object[key] = isInitForm ? this.fb.group(this.pickObjectProperties(workPermitRequest, mapping[key])) : this.pickObjectProperties(workPermitRequest, mapping[key]);
            } else {
                object[key] = isInitForm ? this.fb.array([]) : workPermitRequest[key].map(wpFileAttachment => new WorkPermitFileAttachment(wpFileAttachment));
            }
            return object;
        }, {});
    }

    private read(): void {
        const workPermitRequest: WorkPermitRequest = this.route.snapshot.data['workPermitRequest'];

        if (!workPermitRequest) {
          return;
        }

        if (workPermitRequest.LastReworkComment.length !== null && workPermitRequest.Step === 'REWORK') {
          this.snackBar.open('Les modifications suivantes sont nécessaire: ' + workPermitRequest.LastReworkComment, 'Ok', {
            duration: 5000
          });
        }

        const workPermitFormValue = this.getGlobalForm(workPermitRequest, false);
        this.workPermitRequest = workPermitRequest;

        workPermitRequest.FileAttachments.forEach(file => {
          (this.globalForm.get('FileAttachments') as FormArray).push(this.fb.group(new WorkPermitFileAttachment()));
        });

        this.globalForm.patchValue(workPermitFormValue);
        this.globalForm.get('workDesignation.InterventionStartDate').setValue(new Date(this.workPermitRequest.InterventionStartDate));
        this.globalForm.get('workDesignation.InterventionEndDate').setValue(new Date(this.workPermitRequest.InterventionEndDate));
    }
}
/**
* Attachment Component
**/
export class AttachmentsComponent implements OnInit {
  @Input() form: FormGroup;
  @Input() smartBRE: SmartBRE;
  public isDisabled = false;
  constructor(
    private _formBuilder: FormBuilder,
  ) { }
  ngOnInit() {
    this.attachmentList.valueChanges.subscribe(value => {
      this.isDisabled = this.form.get('FileAttachments').disabled;
    });
    this.isDisabled = this.form.get('FileAttachments').disabled;
  }
  get attachmentList(): FormArray {
    return this.form.get('FileAttachments') as FormArray;
  }
  addAttachment() {
    this.attachmentList.push(
      this._formBuilder.group(new WorkPermitFileAttachment())
    );
  }
  removeAttachment(index) {
    this.attachmentList.removeAt(index);
  }
}
/**
* Request Service
**/
export class WorkPermitRequestService extends DataAccessService<WorkPermitRequest> {
  private workPermitRequestWorkflow: string = this.CONFIG.get()['workflowID']['workPermitRequest'];
  private workPermitRequestResource: string = this.CONFIG.get()['SMOSystemName']['workPermitRequest'];
  constructor(
    injector: Injector,
    private wfService: WorkflowService,
    private associationMapperService: AssociationMapperService,
    private taskService: TaskService,
  ) {
    super(injector, 'workPermitRequest', WorkPermitRequest);
  }
  public getAll(): Observable<Array<WorkPermitRequest>> {
    return this.smoService
      .list<WorkPermitRequest>(this.resource).pipe(
        map(workPermitRequests => workPermitRequests.map(
          workPermitRequest => new WorkPermitRequest(workPermitRequest))
        )
      );
  }
  public getWorkPermitRequest(id: number, includes?: string[]): Observable<WorkPermitRequest> {
    return this.associationMapperService.get((this as any), id, includes);
  }
  public newRequest(workPermitRequest: WorkPermitRequest): Observable<WorkPermitRequest> {
    return this.saveRequest(workPermitRequest).pipe(
        mergeMap(workPermitRequestUpdated => this.wfService.startBusinessWorkflowInstance(
          this.workPermitRequestWorkflow,
          workPermitRequestUpdated.ID
        ))
      );
  }
  public saveRequest(workPermitRequest: WorkPermitRequest): Observable<WorkPermitRequest> {
    return this.associationMapperService.save((this as any), workPermitRequest);
  }
}
/**
* Attachment Service
**/
export class WorkPermitFileAttachmentService extends DataAccessService<WorkPermitFileAttachment> {
  constructor(injector: Injector) {
    super(injector, 'workPermitFileAttachment'); // must call super()
  }
  public save(item: WorkPermitFileAttachment): Observable<WorkPermitFileAttachment> {
    return this.smoService.save<WorkPermitFileAttachment>(this.resource, item['ID'], WorkPermitFileAttachment.flattenToPOJO(item),);
  }
  public list(filters?: any): Observable<Array<WorkPermitFileAttachment>> {
    return this.smoService.list<WorkPermitFileAttachment>(this.resource, filters).pipe(
        map(fileAttachments => fileAttachments.map(file => WorkPermitFileAttachment.createFromFlat(file))),
      );

  }
}
...