I’m building a multi-step form in Angular where users can create a Dungeons & Dragons character. In one of the steps, after the user selects a class (Bard, Cleric), they need to choose one equipment option from a list provided by a dummy data.ts file. Each equipment choice offers either an item or an alternate option.
I need to dynamically populate the equipmentChoice
field in the form based on the selected class. Once populated, the user should be able to choose either the item
or the alternate
for each equipment choice, if item
is selected, alternate
shoud be disabled.
How can I implement this? Have no idea how to do it. Should i change JSON object, or try something else?
data.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
);
}
}
}