как лучше всего следовать принципу DRY?

Мой первый компонент

export class EditIntegrationComponentAttributeComponent implements OnInit {
  constructor(
    private _router: ActivatedRoute,
    private _intApi: IntegrationsApiService,
    private _spinner: SpinnerService,
    private _fb: FormBuilder,
    private _routerNavigation: Router,
    private _notification: NotificationsService,
  ) {
    this.componentAttributeID = this._router.snapshot.params.id;

  }

  ngOnInit(): void {
    this._spinner.showSpinner('loading');
    if (this.isNew) {
      this.sources = {
        componentAttributes: this._intApi.getIntComponentAttributesOptions(),
        componentAttributeType: this._intApi.getIntComponentTypes(),
        allComponentAttribute: this._intApi.getIntComponentAttributes()
      };
    } else {
      this.sources = {
        componentAttributes: this._intApi.getIntComponentAttributesOptions(),
        componentAttribute: this._intApi.getIntComponentAttributeById(this.componentAttributeID),
        componentAttributeType: this._intApi.getIntComponentTypes(),
        allComponentAttribute: this._intApi.getIntComponentAttributes()
      };
    }
    forkJoin(this.sources).pipe(
      finalize(() => {
        this._spinner.hideSpinner();
        this.isLoading = false;
      })
    ).subscribe(
      obj => {
        Object.keys(obj).forEach(key => {
          this[key] = obj[key];
        });
      },
      (er) => {
        // If one call fails then the entire forkjoin fails
        // Display a message telling the user there was a problem pulling data
        console.log(er);
        this.hasLoadingError = true;
      },
      () => {
        this._buildForm(this.componentAttributes);
        this._createSectionNames(this.allComponentAttribute);
        this.filteredOptions = this.iFg.controls.section_name.valueChanges.pipe(
          startWith(''),
          map(val => val.length >= 2 ? this._filter(val) : [])
        );
      }
    );
  }


  /**
   * generating form using the controls created by
   * fn _createControls
   */
  private _buildForm(data) {
    this.iFg = this._fb.group(this._createControls(data));
    console.log(this.iFg)
  }

  /**
   * * Creating form controls by using the option provided by API
   * @params data
   */
  private _createControls(data) {
    const ctrls = {};
    for (const attr in data) {
      let str = {};
      if ( data[attr].type === 'boolean' ) {
      str = {
                [attr]: [{
                  value: this.isNew ? false : this.componentAttribute[attr], disabled: this.isNew ? false : data[attr].read_only
                }]
              };
      } else if ( data[attr].type === 'list' || attr === 'validation_expression' || data[attr].type === 'choice') {
        str = {
          [attr]: [{
            value: this.isNew ? null : this.componentAttribute[attr], disabled: this.isNew ? false : data[attr].read_only
          }]
        };
      } else if ( data[attr].type === 'datetime') {
        str = {
          [attr]: [{
            value: this.isNew ? null : this._formatDate( this.componentAttribute[attr]), disabled: this.isNew ? false : data[attr].read_only
          }]
        };
      } else {
        str = {
          [attr]: [{
            value: this.isNew ? '' : this.componentAttribute[attr], disabled: this.isNew ? false : data[attr].read_only
          }]
        };
      }
      Object.assign(ctrls, str);
    }
    this.isLoading = false;
    this._spinner.hideSpinner();
    return ctrls;
  }

  /**
   * * getter method for checking if component is new or old
   */
  get isNew() {
    return !this.componentAttributeID;
  }

  /**
   * * Save the updated/New Component Attribute
   */
  public saveAttribute() {
    // remove null and empty from data
    this._spinner.showSpinner('saving');
    const obj = this.iFg.value;
    Object.keys(obj).forEach(k => (!obj[k] && obj[k] !== false) &&  delete obj[k]);
    if (!this.isNew) {
      if (this.isTypeChanged) { this.iFg.value.ordering = 1; }
      this._intApi.updateIntComponentAttribute(this.componentAttributeID, obj).subscribe(
        (data) => {
          console.log(data);
          this._spinner.hideSpinner();
          this._notification.success('', 'Component Attribute Updated');
        },
        (err) => {
          console.log(err);
          this._spinner.hideSpinner();
          this._notification.error('', 'Component Attribute can not be updated please check logs');
        }
      );
    } else {
      this._intApi.postIntComponentAttribute(this.iFg.value).subscribe(
        (data) => {
          console.log(data);
          this._notification.success('', 'Component Attribute Added');
          this._spinner.hideSpinner();
          this._routerNavigation.navigateByUrl('/admin/integration/component-attributes/edit/' + data.id);
                   },
        (err) => {
          console.log(err);
          this._spinner.hideSpinner();
          this._notification.error('', 'Component Attribute can not be updated please check console');
        }
      );
    }

  }

  /**
   * * adding choice in the choices array
   */
  public removeChoicesFromList(value): void {
    const index = this.componentAttribute.choices.indexOf(value);

    if (index >= 0) {
      this.componentAttribute.choices.splice(index, 1);
    }
  }

  /**
   * * removing choice from the choices array
   */
  public addChoicesToList(event: MatChipInputEvent): void {
    console.log(this.iFg.value);
    if (this.iFg.value.choices === null || this.iFg.value.choices === '') {
      this.iFg.value.choices = [];
    }
    const input = event.input;
    const value = event.value;
    if ((value || '').trim()) {
      this.iFg.value.choices.push(value.trim());
    }
    // Reset the input value
    if (input) {
      input.value="";
    }
  }

  public deleteComponentAttribute() {
    if (confirm('Are you sure you want to delete Component Attribute')) {
      this._intApi.removeIntComponentAttribute(this.componentAttributeID).subscribe(
        (data) => {
          this._notification.success('', 'Component Attribute deleted successfully');
          this._routerNavigation.navigateByUrl('/admin/integration/component-attributes');
        },
        () => {
          this._notification.warn('', 'Can not delete Component Attribute');
        }
      );
    }
  }


  public onCancel() {
    this._routerNavigation.navigateByUrl('/admin/integration/component-attributes');
  }

  private _formatDate(params: any): string {
    return new Date(params).toLocaleDateString();
  }

  private _filter(value: string): string[] {
    const filterValue = value.toLowerCase();
    return this.options.filter(option => option.toLowerCase().indexOf(filterValue) === 0);
  }

  private _createSectionNames(obj) {
    const key = this.componentAttribute.component_type;
    this.options = [... new Set (obj.filter(attribute => attribute.component_type === key).map(attr => attr.section_name).filter( ob => ob != null))];
  }
}

Мой второй компонент

@Component({
  selector: 'app-edit-note-type',
  templateUrl: './edit-note-type.component.html',
  styleUrls: ['./edit-note-type.component.scss']
})
export class EditNoteTypeComponent implements OnInit {
  private noteTypeID;
  public sources: object;
  public isLoading = false;
  public hasLoadingError = false;
  public noteTypeOptions: IntUrlType[] = [];
  public noteTypeDetails: IntUrlType;
  public noteTypeFg: FormGroup;
  public chk ;
  constructor(
    private _router: ActivatedRoute,
    private _intApi: IntegrationsApiService,
    private _spinner: SpinnerService,
    private _fb: FormBuilder,
    private _routerNavigation: Router,
    private _notification: NotificationsService,
    private _auth: AuthorizationService,
    private _adminApi: AdminApiService
  ) {
    this.noteTypeID = this._router.snapshot.params.id; // for navigation to new server page
  }

  ngOnInit(): void {
    this.isLoading = true;
    this._spinner.showSpinner('loading');
    if (this.isNew) {
      this.sources = {
        noteTypeOptions: this._intApi.getIntNoteCategoriesOptions(),
      };
    } else {
      this.sources = {
        noteTypeOptions: this._intApi.getIntNoteCategoriesOptions(),
        noteTypeDetails: this._intApi.getIntNoteCategoriesById(this.noteTypeID),
      };
    }
    forkJoin(this.sources).pipe(
      finalize(() => {
        this._spinner.hideSpinner();
        this.isLoading = false;
      })
    ).subscribe(
      obj => {
        Object.keys(obj).forEach(key => {
          this[key] = obj[key];
        });
        this.chk = [this.noteTypeOptions];
      },
      (er) => {
        // If one call fails then the entire forkjoin fails
        // Display a message telling the user there was a problem pulling data
        console.log(er);
        this.hasLoadingError = true;
      },
      () => {this._buildForm(this.noteTypeOptions); }
    );
  }
  /**
   * * getter method for checking if component is new or old
   */
  get isNew() {
    return !this.noteTypeID;
  }

  /**
   * generating form using the controls created by
   * fn _createControls
   */
  private _buildForm(data) {
    this.noteTypeFg = this._fb.group(this._createControls(data));
  }
  /**
   * * Creating form controls by using the option provided by API
   * @params data
   */
  private _createControls(data) {
    const ctrls: object = {};
    for (const attr in data) {
      let str = {};
      if ( data[attr].type === 'boolean' ) {
        str = {
          [attr]: [{
            value: this.isNew ? true : this.noteTypeDetails[attr], disabled: this.isNew ? false : data[attr].read_only
          }]
        };
      } else if ( data[attr].type === 'list' || attr === 'validation_expression' || data[attr].type === 'choice') {
        str = {
          [attr]: [{
            value: this.isNew ? null : this.noteTypeDetails[attr], disabled: this.isNew ? false : data[attr].read_only
          }]
        };
      } else if ( data[attr].type === 'datetime') {
        str = {
          [attr]: [{
            value: this.isNew ? null : this._formatDate( this.noteTypeDetails[attr]), disabled: this.isNew ? false : data[attr].read_only
          }]
        };
      } else {
        str = {
          [attr]: [{
            value: this.isNew ? '' : this.noteTypeDetails[attr], disabled: this.isNew ? false : data[attr].read_only
          }]
        };
      }
      Object.assign(ctrls, str);
    }
    this.isLoading = false;
    this._spinner.hideSpinner();
    return ctrls;
  }

  public onCancel() {
    this._routerNavigation.navigateByUrl('/admin/integration/note-type');
  }

  private _formatDate(params: any): string {
    return new Date(params).toLocaleDateString();
  }


  /**
   * * Save the updated/New Note Type
   */
  public saveNoteType() {
    this._spinner.showSpinner('saving');
    const obj = this.noteTypeFg.value;
    Object.keys(obj).forEach(k => (!obj[k] && obj[k] !== false) &&  delete obj[k]);
    if (!this.isNew) {
      this._intApi.updateIntNoteCategory(this.noteTypeID, obj).subscribe(
        (data) => {
          this._spinner.hideSpinner();
          this._routerNavigation.navigateByUrl('/admin/integration/note-type/edit/' + data.id);
          this._notification.success('', 'Successfully Saved');
        },
        (err) => {
          console.log(err);
          this._spinner.hideSpinner();
          this._notification.error('', 'Not Saved! Please check Error in logs');
        }
      );
    } else {
      this._intApi.postIntNoteCategory(this.noteTypeFg.value).subscribe(
        (data) => {
          this._notification.success('', 'Type Added');
          this._spinner.hideSpinner();
          this._routerNavigation.navigateByUrl('/admin/integration/note-type/edit/' + data.id);
        },
        (err) => {
          console.log(err);
          this._spinner.hideSpinner();
          this._notification.error('', 'Not Saved');
        }
      );
    }
  }
  public deleteNoteType() {
    if (confirm('Are you sure you want to delete category')) {
      this._intApi.removeIntNoteCategory(this.noteTypeID).subscribe(
        (data) => {
          this._notification.success('', 'Category deleted successfully');
          this._routerNavigation.navigateByUrl('/admin/integration/note-type');
        },
        () => {
          this._notification.warn('', 'Can not delete');
        }
      );
    }
  }

}

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

0

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *