Updating Field Position Indices in a Dynamic Angular Form Builder with Dependencies

Discussão em 'Angular' iniciado por Ali Hamed, Junho 29, 2025.

  1. Ali Hamed

    Ali Hamed Guest

    Problem:

    I built an Angular 19 form builder with drag-and-drop functionality, structured as:

    Tabs (Pages) → Sections → Fields

    The form works well, but I'm struggling with field dependencies—where one field's visibility/value depends on another.

    Current Approach:

    Each field has a position object storing its location (tab, section, index). However, when fields are rearranged (e.g., inserting a new field shifts others), the stored position indices aren’t updated automatically. This breaks dependencies since other fields may still reference outdated positions.

    Question:

    How can I dynamically track/update field positions in a drag-and-drop form builder to ensure dependencies remain accurate? (pass by reference)


    Code:

    Add new field:

    addField(event: any): void {
    if (event.previousContainer === undefined) return;

    if (this.activeTabSectionIds.includes(event.container.id) && event.previousContainer.id !== 'listFields') {
    transferArrayItem(event.previousContainer.data, event.container.data, event.previousIndex, event.currentIndex);
    const field = this.sectionWithFields.fields[event.currentIndex];
    field.position = {
    tab: { index: this.tabIndex },
    section: { index: this.sectionIndex },
    field: { index: event.currentIndex }
    };
    return;
    }

    const field = { ...event.previousContainer.data[event.previousIndex] }
    field.name = generateUniqueName(field.type);
    field.position = {
    tab: { index: this.tabIndex },
    section: { index: this.sectionIndex },
    field: { index: event.currentIndex }
    };
    this.sectionWithFields.fields.splice(event.currentIndex, 0, field);
    }


    Field template:

    export function createBaseFieldTemplate<T extends BaseField>(
    type: string,
    overrides: Partial<T> = {}
    ): T {
    const baseTemplate: BaseField = {
    name: 'example-123',
    type: type as FieldType,
    label: `${type}Field`,
    required: true,
    isValid: false,
    textColor: '#000000',
    fontSize: '16',
    width: '100',
    // some other attributes goes here ...
    };

    return { ...baseTemplate, ...overrides } as T;
    }

    export function createInputFieldTemplate(): InputField {
    return createBaseFieldTemplate<InputField>('input', {
    icon: 'text_fields',
    inputType: InputType.Text,
    placeholder: 'Enter text here',
    });
    }

    export function createTextareaFieldTemplate(): TextareaField {
    return createBaseFieldTemplate<TextareaField>('textarea', {
    icon: 'text_fields',
    placeholder: 'Enter text here',
    rows: 1,
    value: '',
    });
    }


    Related function:

    relatedFieldsSelected(sourceField: any, targetField: any): void {
    sourceField.depandedFields.push(targetField.position);
    targetField.relatedTo = sourceField.position;
    }


    Image to clarify the idea more:

    [​IMG]

    Continue reading...

Compartilhe esta Página