Angular 13:与组件的遗传和多态性

发布于 2025-02-04 09:59:28 字数 6401 浏览 3 评论 0原文

我的主要问题是“如何呈现由父主形式制成的角度?”。 实际上,我成功地生成了“创建”表单,以您没有完整的对象显示。 但是,当我尝试修改现有元素时,这是一场噩梦。 看来,在创建视图之后,最近将经典的“补丁”方法(形式构成式构建器)非常执行。 由于表格视图部分来自父母,因此实际不是“刷新”。

面对Ngoninit的麻烦,A决定将其从父母身上删除。但是问题仍然存在... 我也可以/应该将父级宣布为“抽象”,但会导致子类错误。 Angular / vscode在“ app.module.ts”上投诉:

类型'type'parentCollectionsFormComponent'无法分配给类型 '任何[] |类型'。类型“ pyteof parentCollectionsFormComponent”是 不能分配给“类型”。 无法将抽象的构造函数分配给非抽象构造函数。

parent-collections-form.component.ts

 /**
 * Classe Mère d'affichage de formulaire d'une Collection
 * @param collectionIcon - string : Nom de l'icône affichée dans le titre du formulaire
 * @param elmtType - string : Le type de collection de l'élément à afficher
 * @param elmtName - string : La dénomination de l'élément manipulé
 * @param elmtID - number : L'identifiant unique, si existant, de l'élément manipulé.
 * en cas de fourniture d'un identifiant, le formulaire bascule en modification/update
 */
@Component({
  selector: 'parent-collections-form',
  templateUrl: './parent-collections-form.component.html',
  styleUrls: ['./parent-collections-form.component.scss']
})
export class ParentCollectionsFormComponent /*implements OnInit*/ {
  @Input() collectionIcon!: string;
  @Input() elmtType!: string;
  @Input() elmtName!: string;
  @Input() elmtID?: number;
  
  element!: CollectionParentModel;
  form?: FormGroup;

  @Output() onFormSubmitOrReject = new EventEmitter<CollectionParentModel | null>();

  constructor(protected readonly fb: FormBuilder, protected dbServ: DatabaseService) { 
    console.log("CONSTRUCTOR PARENT: ");
  }

  protected collectData() : void {
    console.log("PARENT COLLECTING...");
    this.dbServ.getID(this.elmtType, this.elmtID!).subscribe({
      next: (el: CollectionParentModel) => this.element = el/*; console.log(`ELEMENT IS ${JSON.stringify(this.element)}`);}*/,
      error: (err) => console.error(err),
      complete: () => {
        console.log(`Identical names ? ${this.element.name === this.elmtName}`, 'element: ', this.element);
        this.patchForm();
      }
    });

  }

  protected createForm() : void { }

  protected commitData() : void { }

  protected patchForm() : void { }

  /**
  * Traitement des données soumises dans le formulaire
  */
  async onFormSubmitted() : Promise<void> {
    if (this.form?.valid) {
      this.commitData();
      
      if (this.element.id === undefined) {
        //CREATE
        this.element.id === undefined;
        this.dbServ.create(this.elmtType, this.element).subscribe({
          next: (cm: any) => this.element.id = cm.id,
          error: (err) => { console.error(err); this.onFormSubmitOrReject.emit(null)},
          complete: () => this.onFormSubmitOrReject.emit(this.element)
        })
      } else {
        //UPDATE
        this.dbServ.update(`${this.elmtType}/${this.element.id}`, this.element).subscribe({
          //next: (p: Profile) => this.profile.id = p.id,
          error: (err) => { console.error(err); this.onFormSubmitOrReject.emit(null)},
          complete: () => this.onFormSubmitOrReject.emit(this.element)
        })
      };
    }
  }
  
  /**
   * En cas d'annulation du formulaire, emission d'un évènement 'null'
   */
  cancelledForm() : void  {
    //console.log('Canceled!');
    this.onFormSubmitOrReject.emit(null);
  }
}

挑战form.component.ts

    @Component({
  selector: 'challenge-form',
  templateUrl: './challenge-form.component.html',
  styleUrls: ['./challenge-form.component.scss']
})
export class ChallengeFormComponent extends ParentCollectionsFormComponent implements OnInit {
  challenge: ChallengeModel = new ChallengeModel;

  constructor(protected override readonly fb: FormBuilder, protected override dbServ: DatabaseService) { 
    super(fb, dbServ);
    console.log("CHILD");
  }

  ngOnInit(): void {
    console.log("CHILD ON_INIT: ");
    of(this.createForm()).subscribe({
      next: () => {
        console.log('Creation finished');
        if (this.elmtID) {
        this.collectData();
        this.patchForm();
        };
      },
      complete: () => {
        console.log('CollectData ends here');
      }
    })
  }

  protected override createForm() : void {
    console.log('CHILD CREATE FORM');
    this.form = this.fb.group({
      name: [this.elmtName,[Validators.required, Validators.minLength(4), Validators.maxLength(48)]],
      reward: ['', [Validators.required, Validators.maxLength(28)]],
      requiredLevel: [0, [Validators.required]],
      rewardLevel: [0, [Validators.required]],
      step1Name: ['', [Validators.required, Validators.maxLength(48)]],
      step1Description: [''],
      step2Name: ['', [Validators.maxLength(48)]],
      step2Description: [''],
      step3Name: ['', [Validators.maxLength(48)]],
      step3Description: ['']
    })
  }

  protected override patchForm() : void {
    console.log('PATCH FORM!');
    this.form?.patchValue({
      name: this.challenge.name,
      reward: this.challenge.reward,
      requiredLevel: this.challenge.requiredLevel,
      rewardLevel: this.challenge.rewardLevel,
      step1Name: this.challenge.step1Name,
      step1Description: this.challenge.step1Description,
      step2Name: this.challenge.step2Name,
      step2Description: this.challenge.step2Description,
      step3Name: this.challenge.step3Name,
      step3Description: this.challenge.step3Description
    });
  }

  protected override commitData() : void {
    this.challenge.name             = this.form?.controls['name'].value;
    this.challenge.reward           = this.form?.controls['reward'].value;
    this.challenge.requiredLevel    = <number>this.form?.controls['requiredLevel'].value;
    this.challenge.rewardLevel      = <number>this.form?.controls['rewardLevel'].value;
    this.challenge.step1Name        = this.form?.controls['step1Name'].value;
    this.challenge.step1Description = this.form?.controls['step1Description'].value;
    this.challenge.step2Name        = this.form?.controls['step2Name'].value;
    this.challenge.step2Description = this.form?.controls['step2Description'].value;
    this.challenge.step3Name        = this.form?.controls['step3Name'].value;
    this.challenge.step3Description = this.form?.controls['step3Description'].value;
    this.element = this.challenge;
  }
}

感谢您的帮助。

My main problem is "how to render an Angular Form made from a parent Master Form ?".
Actually, I succeed on generating a "creational" form, in a way that you don't have a full object to display.
However, when I try to modify an existing element it's a nightmare.
It appears that the classical "patch" method, form the FormBuilder, is executed very lately after the view is created.
As the form view partially comes from the parent, the actual is not "refreshed".

Facing troubles with ngOnInit, a decided to remove it from parent. But problem still remains...
I could/should also have declared Parent class as "Abstract" but it leads to errors in the Child class. Angular / VSCode complains on the "app.module.ts" :

Type 'typeof ParentCollectionsFormComponent' is not assignable to type
'any[] | Type'. Type 'typeof ParentCollectionsFormComponent' is
not assignable to type 'Type'.
Cannot assign an abstract constructor type to a non-abstract constructor type.

parent-collections-form.component.ts

 /**
 * Classe Mère d'affichage de formulaire d'une Collection
 * @param collectionIcon - string : Nom de l'icône affichée dans le titre du formulaire
 * @param elmtType - string : Le type de collection de l'élément à afficher
 * @param elmtName - string : La dénomination de l'élément manipulé
 * @param elmtID - number : L'identifiant unique, si existant, de l'élément manipulé.
 * en cas de fourniture d'un identifiant, le formulaire bascule en modification/update
 */
@Component({
  selector: 'parent-collections-form',
  templateUrl: './parent-collections-form.component.html',
  styleUrls: ['./parent-collections-form.component.scss']
})
export class ParentCollectionsFormComponent /*implements OnInit*/ {
  @Input() collectionIcon!: string;
  @Input() elmtType!: string;
  @Input() elmtName!: string;
  @Input() elmtID?: number;
  
  element!: CollectionParentModel;
  form?: FormGroup;

  @Output() onFormSubmitOrReject = new EventEmitter<CollectionParentModel | null>();

  constructor(protected readonly fb: FormBuilder, protected dbServ: DatabaseService) { 
    console.log("CONSTRUCTOR PARENT: ");
  }

  protected collectData() : void {
    console.log("PARENT COLLECTING...");
    this.dbServ.getID(this.elmtType, this.elmtID!).subscribe({
      next: (el: CollectionParentModel) => this.element = el/*; console.log(`ELEMENT IS ${JSON.stringify(this.element)}`);}*/,
      error: (err) => console.error(err),
      complete: () => {
        console.log(`Identical names ? ${this.element.name === this.elmtName}`, 'element: ', this.element);
        this.patchForm();
      }
    });

  }

  protected createForm() : void { }

  protected commitData() : void { }

  protected patchForm() : void { }

  /**
  * Traitement des données soumises dans le formulaire
  */
  async onFormSubmitted() : Promise<void> {
    if (this.form?.valid) {
      this.commitData();
      
      if (this.element.id === undefined) {
        //CREATE
        this.element.id === undefined;
        this.dbServ.create(this.elmtType, this.element).subscribe({
          next: (cm: any) => this.element.id = cm.id,
          error: (err) => { console.error(err); this.onFormSubmitOrReject.emit(null)},
          complete: () => this.onFormSubmitOrReject.emit(this.element)
        })
      } else {
        //UPDATE
        this.dbServ.update(`${this.elmtType}/${this.element.id}`, this.element).subscribe({
          //next: (p: Profile) => this.profile.id = p.id,
          error: (err) => { console.error(err); this.onFormSubmitOrReject.emit(null)},
          complete: () => this.onFormSubmitOrReject.emit(this.element)
        })
      };
    }
  }
  
  /**
   * En cas d'annulation du formulaire, emission d'un évènement 'null'
   */
  cancelledForm() : void  {
    //console.log('Canceled!');
    this.onFormSubmitOrReject.emit(null);
  }
}

challenge-form.component.ts

    @Component({
  selector: 'challenge-form',
  templateUrl: './challenge-form.component.html',
  styleUrls: ['./challenge-form.component.scss']
})
export class ChallengeFormComponent extends ParentCollectionsFormComponent implements OnInit {
  challenge: ChallengeModel = new ChallengeModel;

  constructor(protected override readonly fb: FormBuilder, protected override dbServ: DatabaseService) { 
    super(fb, dbServ);
    console.log("CHILD");
  }

  ngOnInit(): void {
    console.log("CHILD ON_INIT: ");
    of(this.createForm()).subscribe({
      next: () => {
        console.log('Creation finished');
        if (this.elmtID) {
        this.collectData();
        this.patchForm();
        };
      },
      complete: () => {
        console.log('CollectData ends here');
      }
    })
  }

  protected override createForm() : void {
    console.log('CHILD CREATE FORM');
    this.form = this.fb.group({
      name: [this.elmtName,[Validators.required, Validators.minLength(4), Validators.maxLength(48)]],
      reward: ['', [Validators.required, Validators.maxLength(28)]],
      requiredLevel: [0, [Validators.required]],
      rewardLevel: [0, [Validators.required]],
      step1Name: ['', [Validators.required, Validators.maxLength(48)]],
      step1Description: [''],
      step2Name: ['', [Validators.maxLength(48)]],
      step2Description: [''],
      step3Name: ['', [Validators.maxLength(48)]],
      step3Description: ['']
    })
  }

  protected override patchForm() : void {
    console.log('PATCH FORM!');
    this.form?.patchValue({
      name: this.challenge.name,
      reward: this.challenge.reward,
      requiredLevel: this.challenge.requiredLevel,
      rewardLevel: this.challenge.rewardLevel,
      step1Name: this.challenge.step1Name,
      step1Description: this.challenge.step1Description,
      step2Name: this.challenge.step2Name,
      step2Description: this.challenge.step2Description,
      step3Name: this.challenge.step3Name,
      step3Description: this.challenge.step3Description
    });
  }

  protected override commitData() : void {
    this.challenge.name             = this.form?.controls['name'].value;
    this.challenge.reward           = this.form?.controls['reward'].value;
    this.challenge.requiredLevel    = <number>this.form?.controls['requiredLevel'].value;
    this.challenge.rewardLevel      = <number>this.form?.controls['rewardLevel'].value;
    this.challenge.step1Name        = this.form?.controls['step1Name'].value;
    this.challenge.step1Description = this.form?.controls['step1Description'].value;
    this.challenge.step2Name        = this.form?.controls['step2Name'].value;
    this.challenge.step2Description = this.form?.controls['step2Description'].value;
    this.challenge.step3Name        = this.form?.controls['step3Name'].value;
    this.challenge.step3Description = this.form?.controls['step3Description'].value;
    this.element = this.challenge;
  }
}

Thanks for your help.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文