我正在 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
);
}
}
}
感谢您伸出援手。据我了解,您尝试根据用户选择的类动态填充
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>
请告诉我我的解决方案是否适合您。祝您的项目一切顺利!