Angular Dynamic Reactive 选择选项表单

问题描述 投票:0回答:1

我正在 Angular 中构建一个多步骤表单,用户可以在其中创建龙与地下城角色。在其中一个步骤中,用户选择一个职业(吟游诗人、牧师)后,他们需要从虚拟 data.ts 文件提供的列表中选择一个设备选项。每个设备选择都提供一个项目或替代选项。
我需要根据所选的类动态填充表单中的

equipmentChoice
字段。填充后,用户应该能够为每个设备选择选择
item
alternate
,如果选择
item
,则应禁用
alternate

我该如何实施?不知道该怎么做。我应该更改 JSON 对象,还是尝试其他方法?

数据.ts

export const equipment: any[] = [
  {
    class: "Barbarian",
    equipment_choices: [
      { item: "greataxe", alternate: "any martial melee weapon" },
      { item: "two handaxes", alternate: "any simple weapon" },
    ],
    standard_equipment: ["explorer's pack", "four javelins"],
  },
  {
    class: "Bard",
    equipment_choices: [
      {
        item: "rapier",
        alternate: ["longsword (if proficient)", "any simple weapon"],
      },
      { item: "diplomat's pack", alternate: "entertainer's pack" },
      { item: "lute", alternate: "any other musical instrument" },
    ],
    standard_equipment: ["leather armor", "dagger"],
  },
  {
    class: "Cleric",
    equipment_choices: [
      { item: "mace", alternate: "warhammer (if proficient)" },
      {
        item: "scale mail",
        alternate: ["leather armor", "chain mail (if proficient)"],
      },
      { item: "light crossbow and 20 bolts", alternate: "any simple weapon" },
      { item: "priest's pack", alternate: "explorer's pack" },
    ],
    standard_equipment: ["shield", "holy symbol"],
  },

creator.component.ts

import { Component } from "@angular/core";
import {
  FormBuilder,
  FormGroup,
  Validators,
  FormArray,
  FormControl,
} from "@angular/forms";
import {
  dndClasses,
  dndRaces,
  dndBackgrounds,
  dndRacialBonuses,
  classArchetypesWithSpells,
  classSkills,
  fightingStyles,
  equipment,
} from "./data";

@Component({
  selector: "app-creator",
  templateUrl: "./creator.component.html",
  styleUrls: ["./creator.component.scss"],
})
export class CreatorComponent {
  // Step and points management
  currentStep = 1;
  abilityPoints = 27;
  maxAbilityPoints = 27;

  // Data sources
  classes = dndClasses;
  races = dndRaces;
  backgrounds = dndBackgrounds;
  racialBonuses = dndRacialBonuses;
  archetype = classArchetypesWithSpells;
  fightingStyles = fightingStyles;
  skills = classSkills;

  // Form and selected data
  characterCreationForm: FormGroup;
  filteredArchetypes: string[] = [];
  classAndBackgroundSkill: string[] = [];
  selectedSkills: string[] = [];
  selectedEquipment: string[] = [];

  constructor(private fb: FormBuilder) {
    this.characterCreationForm = this.fb.group({
      name: ["", [Validators.required, Validators.minLength(1)]],
      race: ["", Validators.required],
      class: ["", Validators.required],
      background: ["", Validators.required],
      abilityScores: this.fb.group({
        strength: [
          8,
          [Validators.required, Validators.min(1), Validators.max(20)],
        ],
        dexterity: [
          8,
          [Validators.required, Validators.min(1), Validators.max(20)],
        ],
        constitution: [
          8,
          [Validators.required, Validators.min(1), Validators.max(20)],
        ],
        intelligence: [
          8,
          [Validators.required, Validators.min(1), Validators.max(20)],
        ],
        wisdom: [
          8,
          [Validators.required, Validators.min(1), Validators.max(20)],
        ],
        charisma: [
          8,
          [Validators.required, Validators.min(1), Validators.max(20)],
        ],
      }),
      archeTypes: ["", Validators.required],
      skills: this.fb.array([], Validators.required),
      equipment_choices: this.fb.array([]),
      standart_equipment: this.fb.array([]),
    });
  }

  // Getters
  get skillsFormArray(): FormArray {
    return this.characterCreationForm.get("skills") as FormArray;
  }

  get equipmentFormArray(): FormArray {
    return this.characterCreationForm.get("equipment") as FormArray;
  }

  get equipmentChoicesControls() {
    return (this.characterCreationForm.get("equipment_choices") as FormArray)
      .controls;
  }
   

  selectEquipment() {
    const selectedClass = this.characterCreationForm.get("class")?.value;
    const selectedEquipment = equipment.find(
      (equip) => equip.class === selectedClass
    );

    console.log("Selected equipment:", selectedEquipment);
  }

  onEquipmentChange(event: any, equipment: any) {
    if (event.target.checked) {
      this.selectedEquipment.push(equipment);
      this.equipmentFormArray.push(new FormControl(equipment));
    } else {
      const index = this.selectedEquipment.indexOf(equipment);
      if (index !== -1) {
        this.selectedEquipment.splice(index, 1);
      }
    }
  }

  // Navigation methods
  nextStep() {
    this.selectArchetype();
    this.selectBackground();
    this.getSkills();
    if (this.currentStep < 4) {
      this.currentStep++;
    }
  }

  prevStep() {
    if (this.currentStep > 1) {
      this.currentStep--;
    }
  }

  onSubmit() {
    if (this.characterCreationForm.valid) {
      this.nextStep();
      this.calculateRacialBonus();
      console.log("Form data:", this.characterCreationForm.value);
    } else {
      console.log(
        "Please fill out all required fields.",
        this.characterCreationForm
      );
    }
  }
}
json angular forms angular-reactive-forms dynamic-forms
1个回答
0
投票

感谢您伸出援手。据我了解,您尝试根据用户选择的类动态填充

equipment_choices
控件,然后允许用户在
item
或其
alternate
之间进行选择。为了实现这一目标,我建议采用以下方法:

更新

selectEquipment
方法以在选择类时动态填充
equipment_choices
控件。

selectEquipment() {
  const selectedClass = this.characterCreationForm.get("class")?.value;
  const selectedEquipment = equipment.find(
    (equip) => equip.class === selectedClass
  );

  const equipmentChoicesFormArray = this.characterCreationForm.get('equipment_choices') as FormArray;
  equipmentChoicesFormArray.clear();  // Clear previous selections

  if (selectedEquipment) {
    selectedEquipment.equipment_choices.forEach(choice => {
      const choiceGroup = this.fb.group({
        selected: [''],  // Placeholder for the user's choice (either item or alternate)
        itemDisabled: [false],  // Control to disable the item if alternate is selected
        alternateDisabled: [false],  // Control to disable the alternate if item is selected
        item: [choice.item],
        alternate: [choice.alternate]
      });

      equipmentChoicesFormArray.push(choiceGroup);
    });
  }
}

添加一个方法来处理选择项目时禁用备用选项的问题,反之亦然。

onSelectionChange(index: number, type: 'item' | 'alternate') {
  const equipmentChoicesFormArray = this.characterCreationForm.get('equipment_choices') as FormArray;
  const choiceGroup = equipmentChoicesFormArray.at(index) as FormGroup;

  if (type === 'item') {
    choiceGroup.patchValue({ itemDisabled: false, alternateDisabled: true });
    choiceGroup.get('selected')?.setValue(choiceGroup.get('item')?.value);
  } else {
    choiceGroup.patchValue({ itemDisabled: true, alternateDisabled: false });
    choiceGroup.get('selected')?.setValue(choiceGroup.get('alternate')?.value);
  }
}

不要忘记在模板中绑定表单控件。由于我无法重现用户界面,因此我无法为您提供太多帮助。这是一个带有单选按钮的简单示例。

<div formArrayName="equipment_choices" *ngFor="let choice of equipmentChoicesControls; let i = index">
  <div [formGroupName]="i">
    <label>
      <input type="radio" formControlName="itemDisabled" [disabled]="choice.get('alternateDisabled')?.value" (change)="onSelectionChange(i, 'item')">
      {{ choice.get('item')?.value }}
    </label>
    <label *ngIf="choice.get('alternate')?.value">
      <input type="radio" formControlName="alternateDisabled" [disabled]="choice.get('itemDisabled')?.value" (change)="onSelectionChange(i, 'alternate')">
      {{ choice.get('alternate')?.value }}
    </label>
  </div>
</div>

请告诉我我的解决方案是否适合您。祝您的项目一切顺利!

© www.soinside.com 2019 - 2024. All rights reserved.