V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
helee9199
V2EX  ›  程序员

新手问个 angular 问题,就是表单数据如何优雅的封装到 model 里

  •  
  •   helee9199 · 1 天前 · 803 次点击

    angular 区不太活跃 故移动此区

    因不可抗力原因要求使用 angular20 开始学这个,然后有个问题很困扰 ,就是一般每个表单都会有个对应的 model 页面上会用 formControlName 。 然后我们的 model 字段很多 在 component 里就有很多这种代码

     const tubeData: TubeModel = {
          commonParams: this.commonParams,
          tubeInitDate: formatDate(formValue.tubeInitDate, 'yyyy/MM/dd HH:mm'),
          tubeInsertionDate: formatDate(formValue.tubeInsertionDate, 'yyyy/MM/dd HH:mm'),
          anticipatedTubeRemovalDate: formatDate(formValue.anticipatedTubeRemovalDate, 'yyyy/MM/dd'),
          tubeId: formValue.tubeId,
          tubeName: formValue.tubeName,
          tubeGroup: formValue.tubeGroup,
          tubeType: formValue.tubeType,
          tubeMaterial: formValue.tubeMaterial,
          tubeProductNumber: formValue.tubeProductNumber,
          tubeProductNumberOtherValue: formValue.tubeProductNumber || '',
          innerLength: formValue.innerLength,
          innerUnit: 'cm',
          bodyPosition: formValue.bodyPosition,
          bodyPart: formValue.bodyPart,
          tubeLength: formValue.tubeLength,
          tubeUnit: 'cm',
          seqNumber: formValue.seqNumber === '其他' ? formValue.seqNumberOther : formValue.seqNumber,
          drainage: formValue.drainage || 0,
          traits: {
            color: formValue.color,
            colorOther: formValue.colorOther || '',
            nature: formValue.nature,
            natureOther: formValue.natureOther || '',
            flavor: formValue.flavor,
            flavorOther: formValue.flavorOther || '',
          },
        };
    
    以及这种
    
          this.form.patchValue({
          tubeGroup: tube.tubeGroup,
          tubeId: tube.tubeId,
          tubeInitDate: tube.tubeInitDate ? new Date(tube.tubeInitDate) : null,
          tubeInsertionDate: tube.tubeInsertionDate ? new Date(tube.tubeInsertionDate) : null,
          anticipatedTubeRemovalDate: tube.anticipatedTubeRemovalDate
            ? new Date(tube.anticipatedTubeRemovalDate)
            : null,
          tubeName: tube.tubeName,
          tubeType: tube.tubeType,
          tubeMaterial: tube.tubeMaterial,
          tubeProductNumber: tube.tubeProductNumber,
          innerLength: tube.innerLength,
          bodyPosition: tube.bodyPosition,
          bodyPart: tube.bodyPart,
          tubeLength: tube.tubeLength,
          seqNumber: tube.seqNumber,
          drainage: tube.drainage,
        });
    
    还有 init 的时候这种
    
          ngOnInit(): void {
        this.form = this.fb.group({
          tubeGroup: [null],
          tubeId: [null],
          tubeInitDate: [null],
          tubeInsertionDate: [null],
          anticipatedTubeRemovalDate: [null],
          tubeName: [null],
          tubeType: [''],
          tubeMaterial: [null],
          tubeProductNumber: [null],
          innerLength: [null],
          bodyPosition: [null],
          bodyPart: [''],
          tubeLength: [null],
          seqNumber: [null],
          seqNumberOther: [''],
          drainage: [null],
          color: [null],
          colorOther: [''],
          flavor: [null],
          flavorOther: [''],
          nature: [null],
          natureOther: [''],
        });
    
      }
    

    我觉得看着很冗余 字段多了一刷一大片 既然有了 model ,有办法简化这部分吗

    15 条回复    2025-11-25 10:08:22 +08:00
    c3de3f21
        1
    c3de3f21  
       1 天前
    signal 和 effect 可以吗,都是比较新的 API?

    model = signal<User>({ name: '', age: 0 });

    form = new FormGroup({
    name: new FormControl(''),
    age: new FormControl(0),
    });


    effect(() => {
    this.form.patchValue(this.model());
    });


    effect(() => {
    this.model.update(m => ({ ...m, ...this.form.value }));
    });
    helee9199
        2
    helee9199  
    OP
       1 天前
    @c3de3f21 你举的例子只有两个属性。但是我想问的是 如果我有 50 个属性,怎么优雅的处理。
    就是想优化 form = new FormGroup({
    name: new FormControl(''),
    age: new FormControl(0),
    });这部分 ,感觉很啰嗦, 有没有办法实现,因为我是 java ,有没有办法 通过 model 的 class 自动处理这部分?
    shakaraka
        3
    shakaraka  
    PRO
       1 天前
    1 、21 新增了 signal form ,可以尝试。
    2 、标准的写法是:先在 class 里定义好 FormGroup 以及默认值,然后在 init 里或者 http reponse 后进行 patchValue

    我不太懂你的 model 是什么,ng 里没这个概念。首先你得知道 form 的数据结构和后台给你的数据结构是两回事,需要赋值是标准操作
    shakaraka
        4
    shakaraka  
    PRO
       1 天前
    @helee9199 #2 先定义结构,后早操作数据是很正常的编码方式。除非你不在乎类型全程 any ,我有其他方法
    c3de3f21
        5
    c3de3f21  
       1 天前
    @shakaraka #3 他是想类似 vue 的那种,就好像我 new 一个 Person ,然后直接用双绑
    c3de3f21
        6
    c3de3f21  
       1 天前
    ReactiveForm 或者 FormModule ,与 NgModel 选一种,后者更像是你说的那种,可是没有验证
    shakaraka
        7
    shakaraka  
    PRO
       1 天前
    @c3de3f21 #5 只有 21 版的 signal form 体验会好很多。旧版的就按照原始的标准做法做就行了,没 vue 那种
    helee9199
        8
    helee9199  
    OP
       1 天前
    @shakaraka 我去 怎么这么快 上周还是 20 怎么就 21 了。。。
    helee9199
        9
    helee9199  
    OP
       1 天前
    @shakaraka 就是例如我后台要存资料 这笔资料有 50 个属性 ,前端我也会写一个 50 个属性的 interface 或者 class 也就是我所说的 model 。
    然后保存数据的时候封装成这个 model 传给后台
    目前页面上会写 formControlName='beanName'
    然后这种做法就会出现我主楼里那种罗嗦的写法。
    shakaraka
        10
    shakaraka  
    PRO
       1 天前
    @helee9199 #8 很久官方就预告 20 号出了。你没关注
    shakaraka
        11
    shakaraka  
    PRO
       1 天前
    @helee9199 #9 首先你写 java 肯定知道 DTO 、VO 这些鬼东西。

    先抛开 ng 的 FormGroup ,换个角度想,后端给你定义的数据类型,只是交换数据而已,彼此沟通所需要的内容而已。

    但是你页面上,还有控制你页面的属性、字段等,这些后端是不需要的,所以在页面上是会有自己的一套数据结构。

    你不能想当然把交换数据的结构当做是你页面上要用到的结构。

    一个一个转换、赋值是最稳妥、最一目了然的做法。
    helee9199
        12
    helee9199  
    OP
       1 天前
    @shakaraka 啊 一个一个写转换赋值那这也太蠢了吧,init 的时候要做一遍 数据提交的时候又要做一遍, 真的没有什么方法或者组件能实现 页面上的 beanname 和 model 对应上了就能自动封装的操作吗?
    也就是 springmvc 那种模式。form 里的 name 和 model 的 beanname 对应上 自动封装数据。
    shakaraka
        13
    shakaraka  
    PRO
       1 天前   ❤️ 1
    @helee9199 #12

    并不会。而且现在 21 版本有了 signal form ,总体来说会好用很多。



    你可以看看这个视频,不管用不用 signal form ,还是 vue 那种,我上面说的逻辑还是不变的。

    你始终需要先定义,再使用,这个是个最佳实践方式。特别像是在 vue2 的时候,你动态给 data 赋值,新手还出现很多赋值了,页面没反应,又或者是表单找不到 data 里的数据了,等等。

    https://www.bilibili.com/video/BV1Nys4zvEmr
    helee9199
        14
    helee9199  
    OP
       1 天前   ❤️ 1
    @shakaraka 好吧,这个问题纠结了三四天了,因为就是想找个办法解决这个痛点,工作进度一直卡着在。
    也能是 java 后端的僵化思维吧,带着 java 的思维搞 angular 。
    你这个视频确实是有些启发。既然是这样 还是老老实实的写吧。
    感谢了~
    nzbin
        15
    nzbin  
       14 小时 57 分钟前
    先不用考虑 signal form ,对于小白来说,你的需求首选就是 Reactive Form

    第一:50 个字段不算多,一般就是初始化定义一次,用的就是 this.form = this.fb.group
    第二:提交的时候直接用 this.form.value (或者 this.form.rawValue ,禁用的字段也能取出) 获得表单值就可以,不需要额外处理了(特殊情况可能会对某几个字段处理)
    第三:想要做到第二点可能需要自定义表单控件,不过大部分组件库的大部分组件应该都满足,考虑到业务的多样性,很多情况是满足不了的,比如有一个布尔类型的字段,前端组件库处理都是 true 或者 false ,但是后端要求传值是 1 和 0 ,那直接绑定就不行了,提交的时候肯定要后处理,但是你可以定义一个 <app-checkbox /> 的组件,内部做转换,form.value 的值不用后处理了
    第四:patchValue(object) 就行啊,也不用一个一个字段写出来,后端的返回数据和提交数据应该都一样吧,特殊不一样的字段单独处理就行

    当然,对于新手来说,不用考虑第三点,先用 form.value 取值,最后需要处理的字段单独处理就行了
    关于   ·   帮助文档   ·   自助推广系统   ·   博客   ·   API   ·   FAQ   ·   Solana   ·   1296 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 17:05 · PVG 01:05 · LAX 09:05 · JFK 12:05
    ♥ Do have faith in what you're doing.