新手问个 angular 问题,就是表单数据如何优雅的封装到 model 里 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
helee9199
V2EX    程序员

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

  •  
  •   helee9199 6 小时 7 分钟前 451 次点击

    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 ,有办法简化这部分吗

    14 条回复    2025-11-24 20:14:22 +08:00
    c3de3f21
        1
    c3de3f21  
       5 小时 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
       4 小时 51 分钟前
    @c3de3f21 你举的例子只有两个属性。但是我想问的是 如果我有 50 个属性,怎么优雅的处理。
    就是想优化 form = new FormGroup({
    name: new FormControl(''),
    age: new FormControl(0),
    });这部分 ,感觉很嗦, 有没有办法实现,因为我是 java ,有没有办法 通过 model 的 class 自动处理这部分?
    shakaraka
        3
    shakaraka  
    PRO
       4 小时 48 分钟前
    1 、21 新增了 signal form ,可以尝试。
    2 、标准的写法是:先在 class 里定义好 FormGroup 以及默认值,然后在 init 里或者 http reponse 后进行 patchValue

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

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

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

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

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

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



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

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

    https://www.bilibili.com/video/BV1Nys4zvEmr
    helee9199
        14
    helee9199  
    OP
       2 小时 0 分钟前   1
    @shakaraka 好吧,这个问题纠结了三四天了,因为就是想找个办法解决这个痛点,工作进度一直卡着在。
    也能是 java 后端的僵化思维吧,带着 java 的思维搞 angular 。
    你这个视频确实是有些启发。既然是这样 还是老老实实的写吧。
    感谢了~
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2906 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 14:15 PVG 22:15 LAX 06:15 JFK 09:15
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86