【问题标题】:Reactive or template form?反应式或模板形式?
【发布时间】:2020-04-05 09:29:56
【问题描述】:

这更像是一个基于方法的问题,而不是一个编码问题。我必须创建一个包含 3 个字段的表单,即名称、描述和文本

这就是我的 mod.ts 的样子。

mod.ts

export interface Mod {
  id: number,
    name ? : string,
    clauseList: Clause
}

export interface Clause {
  cName ? : string,
    cid ? : number,
    description: string,
    id ? : number,
    text ? : Text
}


export interface Text {
  cid: number
  txt ? : string,
    tid ? : number

}

我的第一个问题是我应该为这个项目选择模板驱动表单还是响应式表单?

第三个字段的要求之一是每次用户点击输入时,tid 应该增加 1,并且用户输入的任何内容都应该保存为不同的表单组。 cid 应该是 Clause 对象的。 例如:

txt = "hi",
tid =1,
cid = 1 

回车后

txt = "welcome to our shop",
tid = 2,
cid = same as above

谁能帮我解决这个问题? 为了更好的参考,我将发布另一个使用相同格式的问题,它可能会帮助您更好地解决这个问题TypeScript for loop in a nested Array?

我的隐形眼镜干了,我盯着屏幕太久了。请向我询问更多说明。愿原力与你同在。

【问题讨论】:

  • 基于意见/推荐的问题是 Stack Overflow 上的 off-topic,您可以在此处的答案中看到原因 - 多个人都支持两者,而访问者无法知道哪一方是正确的。
  • @OleksandrVetoshkin 我不认为这是重复的,我已经要求人们帮助我解决特定问题,并询问我应该实施哪种方法

标签: javascript angular typescript angular7 angular-forms


【解决方案1】:

使用响应式表单

原因:- 轻松创建动态表单组 dynamic form

  • 表单的全部控制权在您手中。
  • 高度可单元测试

【讨论】:

    【解决方案2】:

    使用模板表单

    更容易学习和维护。

    无需双重处理数据,只需将模型绑定到模板,而不必创建表单对象并将它们绑定到模板。

    易于创建可重用的验证属性,比反应式验证器更像样板,但功能相同。

    高度可单元测试,并且您正在测试实际的模板绑定,而不仅仅是在您的模板中可能被错误绑定的对象。您只需要等待组件更新即可轻松抽象为辅助函数。

    【讨论】:

    • 使用响应式表单,您可以从 TS 文件本身操作表单,这比模板驱动的表单方便得多
    • 作为段落输入细节的第三个字段最让我困惑。我知道我可以动态添加字段,但根据要求它应该是一个文本框(就像这个评论 tb),每次我按下输入时,都应该自动创建一个新的隐藏输入字段。像其中之一“请输入您的技能,以 Enter 分隔或在不同的行中”输入。我们可以使用模板驱动的表单来做到这一点吗?如果是的话,你能分享一些可以帮助我的东西吗?
    • 模板表单的关键是每个表单字段都需要一个唯一的名称,因此您需要类似 [name]="'description_' + i" 的名称,其中 i 是索引。做一个 StackBlitz,我可以帮助你让它工作。
    • 这是我现在需要帮助的事情。您还可以向我展示如何在输入字段中添加段落。这是link
    【解决方案3】:

    这取决于您的要求。假设您必须创建一些登录/注册表单,验证就会出现,并显示被视为良好用户体验的内联验证错误消息,而不是在某些 Toastr 中。对于这种情况,使用“反应形式”。对于简单的表单或只是为了收集某种数据,您可以使用模板驱动的表单。

    在每个键上保存值 Enter:

    HTML:

    TS:

    public formVal = [];
    txt = '';
    name = '';
    desc = '';
    
    onEnter(event) {
        if (event && event.keyCode === 13) {
            const obj = {
                name: this.name,
                desc: this.desc,
                txt: this.txt
            };
            formVal.push(obj);
        }
    }
    

    【讨论】:

    • 模板表单的验证还是比较容易的,没有用模板表单解决不了的用例。
    • 我不需要在我的表单中进行验证,让我担心的是第三个字段的功能。我不知道怎么做。
    • @MenimE,您可以维护一个全局数组以对象格式推送所需的值。编写按键事件,在此事件中检查'event.keyCode ==='13',它是'输入'按钮键码。如果匹配,则将对象推入数组。这样您将拥有此数组中保存的所有值
    • 所以这是我从您的评论中“获取”的内容,我使用 Reactive Form 创建了一个输入字段,查找事件并将数据推送到数组中?
    • 是的..您可以使用反应式表单并推送该表单对象,也可以将 ngModel 提供给所有字段并访问 TS 文件和框架对象中的这些值,然后按上述更新的方式推送答案。 txt = '';名称 = '';描述 = '';是 ts 变量,在 html 中,您可以将这些变量用于 ngModel,例如 '
    【解决方案4】:

    Reactive Forms 提供了丰富的 API 来管理任何复杂的表单,它具有高度的可测试性和可维护性,它允许您轻松创建动态表单并应用复杂的验证,因此它几乎适用于所有表单。当您只需要绑定一些输入而无需任何验证时,模板表单仅适用于一些简单的事情,例如搜索字段。

    【讨论】:

    • 响应式表单没有模板表单无法实现的复杂性。在 AngularJs 中我们没有反应式表单,而在 Angular 模板表单中更好。
    • @AdrianBrand,模板驱动的表单更难阅读、测试和维护,它是一个遗留解决方案,使用模板表单没有任何好处。
    • 这不是真的!
    • @AdrianBrand,你为什么这么想?
    • 模板表单需要双重处理,您需要构建表单对象,然后将表单对象绑定到您的模板。构建验证器有更多样板,但是一旦你拥有它们的库,它们就非常容易应用。它们对于初级开发人员来说更容易学习和维护。测试有点困难,因为它们是异步的,但我已经构建了测试助手,使编写测试变得非常容易,不仅测试表单,还测试模板绑定。
    【解决方案5】:

    这是对问题的实际答案,而不仅仅是模板表单与反应式表单。我在这个答案中使用模板表单。

    https://stackblitz.com/edit/angular-bmcapk

    拥有一系列你的模组

    mods = [{ id: 0 }]; // This is a simplified model for mod, but demonstrates the principal.
    

    在模板中

    <ng-container *ngFor="let mod of mods">
      <label>
        Name<input [name]="'name_' + mod.id" [(ngModel)]="mod.name" autoFocus>
      </label><br>
      <label>
        Desc
        <input [name]="'description_' + mod.id" [(ngModel)]="mod.description">
      </label><br>
      <textarea [name]="'text_' + mod.id" [(ngModel)]="mod.text" (keydown)="checkKey($event)"></textarea><br>
    </ng-container>
    

    遍历 mods 数组并将每个 mod 绑定到您的表单,使用 id 为每个表单字段创建唯一名称。

    checkKey(e) {
      if (e.keyCode === 13) {
        this.mods.push({ id: this.mods[this.mods.length - 1].id + 1 });
        e.preventDefault();
      }
    }
    

    在文本字段中,我有一个 keydown 检查以查看是否已按下 enter。如果它已经向数组添加了另一个具有递增 id 的 mod 并阻止默认停止将新行添加到文本框。

    名称上还有一个名为 autoFocus 的指令,因此当它首次出现时,焦点会从文本中获取并放在新创建的 mod 的名称上。

    @Directive({
        selector: '[autoFocus]'
    })
    export class AutofocusDirective {
      public constructor(private el: ElementRef) {
        setTimeout(() => { el.nativeElement.focus(); });
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2019-09-08
      • 1970-01-01
      • 2016-09-04
      • 2021-04-02
      • 1970-01-01
      • 2017-12-29
      • 2020-05-05
      • 2019-05-23
      • 1970-01-01
      相关资源
      最近更新 更多