【问题标题】:Kind of recursive usage of an Component possible?可以递归使用组件吗?
【发布时间】:2026-02-08 05:35:01
【问题描述】:

在搜索了大约两个小时的解决方案后,我决定询问一些专业人士,他们怀疑解决方案可能非常简单。

这是一个 Angular7 项目。 我想在我的目标组件中有一个带有“+”按钮的“目标”。当您单击该按钮时,我希望将另一个目标添加到页面中。所以我想点击目标组件的一个按钮来创建一个新目标,这对我来说有点像递归。

goals.component.html:

<input type="text" value="Ich brauche einen Laptop für maximal 1000 Euro.">
<br/>
<br/>
<app-goal id="{{lastGivenId+1}}"></app-goal>

goals.component.ts:

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-goals',
  templateUrl: './goals.component.html',
  styleUrls: ['./goals.component.scss']
})
export class GoalsComponent implements OnInit {
  lastGivenId: number = 0;
  constructor() { }

  ngOnInit() {
  }

}

goal.component.ts 和goal.component.html:

//Typescript code
import { Component, OnInit, Input } from '@angular/core';

@Component({
  selector: 'app-goal',
  templateUrl: './goal.component.html',
  styleUrls: ['./goal.component.scss']
})
export class GoalComponent implements OnInit {
  @Input() id : number;

  constructor() { }

  ngOnInit() {
  }
  onAddLowerGoal(currentGoalID:number){
    // var goalElement = document.registerElement('app-goal');
    // document.body.appendChild(new goalElement());
    let newGoal = document.createElement("app-goal");
    newGoal.setAttribute("id", "999");
    let currentGoal = document.getElementById(currentGoalID.toString());
    document.body.insertBefore(newGoal, currentGoal);
  }
}
<html>
<div id="{{id}}" class="goal">goal{{id}}</div>
<button id="AddLowerGoal1" (click)="onAddLowerGoal(999)">+</button>
</html>

这样,它创建了一个 app-goal 元素,但是 app-goal 元素中的 div 和 button 元素丢失了。 如何解决这个问题?欢迎任何帮助。提前致谢。

【问题讨论】:

    标签: html angular typescript components


    【解决方案1】:

    第一眼:从goal.component.html 文件中删除html 标签。

    下一步:您可以使用 Angular 递归添加 app-goal。以javascript方式插入app-goal元素只会添加&lt;app-goal&gt;&lt;/app-goal&gt;对象。它不会创建角度组件。它不会绑定您的数据。

    此外,如果您使用 Angular 的 @Input,您需要使用方括号分配组件输入。不要使用标签。

    goals.component.html:

    <input type="text" value="Ich brauche einen Laptop für maximal 1000 Euro.">
    <br/>
    <br/>
    <app-goal [id]="lastGivenId+1"></app-goal>
    

    goal.component.html:

    <div id="{{id}}" class="goal">goal{{id}}</div>
    <button id="AddLowerGoal1" (click)="onAddLowerGoal(999)">+</button>
    <div *ngFor="let subGoal of subGoals">
      <app-goal [id]="subGoal.id"></app-goal>
    </div>
    

    目标.component.ts:

    import { Component, OnInit, Input } from '@angular/core';
    
    @Component({
      selector: 'app-goal',
      templateUrl: './goal.component.html',
      styleUrls: ['./goal.component.scss']
    })
    export class GoalComponent implements OnInit {
      @Input() id : number;
      subGoals: Array<any> = [];
    
      constructor() { }
    
      ngOnInit() { }
    
      onAddLowerGoal(currentGoalID: number){
        this.subGoals.push({id: currentGoalID});
      }
    }
    

    您还可以使用服务来存储您的目标和子目标,以便以后访问它们。

    【讨论】:

      【解决方案2】:

      我认为您正在寻找的是带有FormArray 的响应式表单,并带有动态添加的表单控件。

      看看这个例如:

      import { Component } from '@angular/core';
      import { FormControl, FormGroup, FormArray, FormBuilder } from '@angular/forms';
      
      @Component({...})
      export class GoalsComponent  {
      
        goalsForm: FormGroup;
      
        constructor(private fb: FormBuilder) {}
      
        ngOnInit() {
          this.goalsForm = this.fb.group({
            goals: this.fb.array([])
          });
        }
      
        onFormSubmit() {
          console.log('Form Value: ', this.goalsForm.value);
        }
      
        get goals() {
          return (<FormArray>this.goalsForm.get('goals')).controls;
        }
      
        addGoal() {
          (<FormArray>this.goalsForm.get('goals')).push(this.fb.control(null));
        }
      
      }
      

      下面是这个模板:

      <h2>Goals:</h2>
      <form [formGroup]="goalsForm" (submit)="onFormSubmit()">
        <button type="button" (click)="addGoal()">Add Goal</button>
        <hr>
        <div *ngFor="let goal of goals; let i = index;" formArrayName="goals">
          <div>
            <label for="goal">Goal {{ i + 1 }}: </label>
            <input type="text" id="goal" [formControlName]="i">
          </div>
          <br>
        </div>
        <hr>
        <button>Submit Form</button>
      </form>
      

      这里有一个Sample StackBlitz 供您参考。

      【讨论】:

      • 非常感谢您的回答。但是我希望在您的 Sample StackBlitz 中发生的是,当单击“添加”按钮时,会出现另一个“添加”按钮。问题是我想要有一个更高的目标,并且能够为那个更高的目标创建一个更低的目标。
      • 那么每个较低的目标会有自己的较低的目标吗?
      • 没错。每个目标(上限或下限)都可以有它自己的下限目标,但不是必须的。
      • 一个上层目标也可以有多个下层目标。每个目标都应该有一个名称(我使用了一个 div 元素来显示名称)并且它是添加按钮来创建一个较低的目标。
      最近更新 更多