You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于ngx-formly实现JSON定义的多页面表单配置方案求教

基于ngx-formly实现JSON驱动的多步骤表单方案

我之前做过不少基于ngx-formly的多步骤表单项目,结合你提到的「人口统计+保险信息」两页的需求,给你几个实操性拉满的方案,都是我实际项目里验证过的,分享给你:

方案一:按页面分组的JSON配置 + 手动页面切换(最直观)

这是最容易上手的方案,核心思路是把你的JSON配置按页面拆分为数组,在组件里维护当前页码,切换时渲染对应页面的字段。

示例JSON配置

{
  "pages": [
    {
      "pageTitle": "人口统计信息",
      "fields": [
        {
          "key": "firstName",
          "type": "input",
          "templateOptions": {
            "label": "FirstName",
            "required": true
          }
        },
        {
          "key": "lastName",
          "type": "input",
          "templateOptions": {
            "label": "LastName",
            "required": true
          }
        },
        {
          "key": "ssn",
          "type": "input",
          "templateOptions": {
            "label": "SSN",
            "required": true
          }
        },
        {
          "key": "dob",
          "type": "datepicker",
          "templateOptions": {
            "label": "Date of Birth",
            "required": true
          }
        }
      ]
    },
    {
      "pageTitle": "保险信息",
      "fields": [
        {
          "key": "insurance.company",
          "type": "input",
          "templateOptions": {
            "label": "Insurance Company",
            "required": true
          }
        },
        {
          "key": "insurance.policy",
          "type": "input",
          "templateOptions": {
            "label": "Policy Number",
            "required": true
          }
        }
      ]
    }
  ]
}

组件实现代码

import { Component } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { FormlyFieldConfig } from '@ngx-formly/core';

@Component({
  template: `
    <form [formGroup]="form" (ngSubmit)="handleSubmit()">
      <h2>{{ currentPage.pageTitle }}</h2>
      <formly-form 
        [form]="form" 
        [fields]="currentPage.fields" 
        [model]="formModel">
      </formly-form>

      <div class="form-actions">
        <button type="button" *ngIf="currentPageIndex > 0" (click)="goToPrevPage()">上一页</button>
        <button type="submit" *ngIf="currentPageIndex === pages.length - 1">提交表单</button>
        <button type="button" *ngIf="currentPageIndex < pages.length - 1" (click)="goToNextPage()" [disabled]="!form.valid">下一页</button>
      </div>
    </form>
  `,
  styles: [`
    .form-actions { margin-top: 20px; gap: 10px; display: flex; }
  `]
})
export class MultiStepFormComponent {
  form = new FormGroup({});
  formModel: any = {};
  // 这里可以从服务端获取上述JSON的pages数组,或者直接硬编码
  pages: { pageTitle: string; fields: FormlyFieldConfig[] }[] = [
    /* 页面1和页面2的配置内容 */
  ];
  currentPageIndex = 0;

  get currentPage() {
    return this.pages[this.currentPageIndex];
  }

  goToNextPage() {
    if (this.form.valid) {
      this.currentPageIndex++;
    }
  }

  goToPrevPage() {
    this.currentPageIndex--;
  }

  handleSubmit() {
    if (this.form.valid) {
      console.log('提交的完整数据:', this.formModel);
      // 这里对接你的提交接口
    }
  }
}

方案优缺点

  • ✅ 优点:JSON结构清晰,和页面一一对应,不需要额外自定义组件,开发成本低
  • ❌ 缺点:如果页面之间有复杂的依赖逻辑(比如某个字段值决定下一页的字段),需要额外处理字段的显隐或动态修改pages数组

方案二:拆分为自定义Formly组件(适合复杂页面逻辑)

如果每个页面有独立的业务逻辑、自定义校验或者特殊交互,推荐把每个页面封装成独立的Formly自定义字段组件,父组件通过FormGroup管理所有子页面的表单状态。

步骤1:定义自定义页面组件

比如人口统计页面组件:

import { Component } from '@angular/core';
import { FieldType, FieldTypeConfig } from '@ngx-formly/core';
import { FormlyFieldConfig } from '@ngx-formly/core';

@Component({
  selector: 'formly-demographics-page',
  template: `
    <div *ngIf="isCurrentPage">
      <h2>人口统计信息</h2>
      <formly-form 
        [form]="field.formControl" 
        [fields]="pageFields" 
        [model]="field.model">
      </formly-form>
    </div>
  `,
})
export class DemographicsPageComponent extends FieldType<FieldTypeConfig> {
  // 当前页面的字段配置
  pageFields: FormlyFieldConfig[] = [
    { key: 'firstName', type: 'input', templateOptions: { label: 'FirstName', required: true } },
    { key: 'lastName', type: 'input', templateOptions: { label: 'LastName', required: true } },
    // SSN、DOB字段配置...
  ];

  // 通过父组件传入的当前页码判断是否显示
  get isCurrentPage() {
    return this.props['activePageIndex'] === 0;
  }
}

保险信息页面组件类似,只需要修改字段配置和isCurrentPage的判断条件。

步骤2:父组件配置与实现

import { Component } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { FormlyFieldConfig } from '@ngx-formly/core';
// 导入自定义组件
import { DemographicsPageComponent } from './demographics-page.component';
import { InsurancePageComponent } from './insurance-page.component';

@Component({
  template: `
    <form [formGroup]="form" (ngSubmit)="handleSubmit()">
      <formly-form 
        [form]="form" 
        [fields]="formFields" 
        [model]="formModel"
        [options]="{ props: { activePageIndex: currentPageIndex } }">
      </formly-form>

      <div class="form-actions">
        <button type="button" *ngIf="currentPageIndex > 0" (click)="goToPrevPage()">上一页</button>
        <button type="submit" *ngIf="currentPageIndex === 1">提交表单</button>
        <button type="button" *ngIf="currentPageIndex < 1" (click)="goToNextPage()" [disabled]="!form.valid">下一页</button>
      </div>
    </form>
  `,
})
export class MultiStepFormComponent {
  form = new FormGroup({});
  formModel: any = {};
  currentPageIndex = 0;

  // 表单字段配置,引用自定义页面组件
  formFields: FormlyFieldConfig[] = [
    {
      key: 'demographics',
      type: 'demographics-page',
      props: { activePageIndex: this.currentPageIndex },
    },
    {
      key: 'insurance',
      type: 'insurance-page',
      props: { activePageIndex: this.currentPageIndex },
    },
  ];

  // 别忘了在模块里声明并注册自定义组件
  // ...

  goToNextPage() {
    if (this.form.valid) {
      this.currentPageIndex++;
    }
  }

  goToPrevPage() {
    this.currentPageIndex--;
  }

  handleSubmit() {
    if (this.form.valid) {
      console.log('提交数据:', this.formModel);
    }
  }
}

方案优缺点

  • ✅ 优点:页面逻辑完全解耦,每个页面可以独立维护自己的业务逻辑、校验规则,扩展性强
  • ❌ 缺点:需要编写多个自定义组件,配置相对繁琐,适合复杂场景

方案三:利用ngx-formly的Steps扩展(最省心)

如果你使用的是@ngx-formly/bootstrap、@ngx-formly/material等带UI组件的扩展库,大部分都内置了steps字段类型,可以直接在JSON里配置步骤,不需要自己写页面切换逻辑。

示例JSON配置

{
  "fields": [
    {
      "type": "steps",
      "props": {
        "steps": [
          {
            "label": "人口统计信息",
            "fields": [
              // 人口统计字段配置...
            ]
          },
          {
            "label": "保险信息",
            "fields": [
              // 保险字段配置...
            ]
          }
        ]
      }
    }
  ]
}

组件实现

只需要简单渲染Formly表单即可,Steps组件会自动处理导航、页面切换、进度显示等逻辑:

import { Component } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { FormlyFieldConfig } from '@ngx-formly/core';

@Component({
  template: `
    <form [formGroup]="form" (ngSubmit)="handleSubmit()">
      <formly-form 
        [form]="form" 
        [fields]="formFields" 
        [model]="formModel">
      </formly-form>
    </form>
  `,
})
export class MultiStepFormComponent {
  form = new FormGroup({});
  formModel: any = {};
  formFields: FormlyFieldConfig[] = [
    // 上述JSON的fields数组内容
  ];

  handleSubmit() {
    if (this.form.valid) {
      console.log('提交数据:', this.formModel);
    }
  }
}

方案优缺点

  • ✅ 优点:零成本实现步骤导航、进度条等UI,不需要自己写切换逻辑,开发效率极高
  • ❌ 缺点:依赖对应的UI扩展库,自定义样式或逻辑的灵活性稍弱

实操注意事项

  1. 校验处理:切换页面时一定要检查当前页面表单的有效性,避免用户跳过必填项;如果需要跨页面校验,可以在提交前统一检查整个FormGroup的状态。
  2. 数据组织:所有页面的模型是同一个对象,建议用嵌套key(比如insurance.company)来分类数据,提交时直接拿到完整的结构化数据。
  3. 进度保存:如果需要支持用户中途退出再返回,可以把formModel存在localStorage或后端,进入页面时恢复数据。
  4. 动态页面:如果需要根据用户选择动态添加/移除页面,可以在组件里修改pages数组或formFields数组,ngx-formly会自动重新渲染表单。

内容的提问来源于stack exchange,提问作者dodegaard

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 08:37:20