Angular2 beta:嵌套基于表单的父/子组件并从父级进行验证

2023-12-31

我正在尝试在 Angular2(Plunker 中带有 TS 的 beta 0)中实现一个具有 2 个嵌套表单的场景,每个表单由一个组件表示。

父组件是Word,它代表假字典中的单词。子组件是WordSense's,每个都代表父词的一种含义。

两个组件都使用模型驱动的表单,子表单使用以下方式将其模型的值绑定到表单控件:ngModel。这样,父组件可以轻松地将其单词的含义传递给子组件,而 2 向绑定则完成其余的工作。

两个表单都附加了简单的自定义验证器。除此之外,我想不仅在单词形式无效时禁用提交按钮,而且在其任何含义无效时也禁用提交按钮。为此,我添加了一个isValid正在编辑的模型的属性,以及用于观察感知表单变化的代码:每当发生变化时,我都会检查表单的valid属性并相应地设置模型的属性。然后,我可以轻松地在视图和代码中的父组件级别添加检查,以便仅当两种形式都正常时我才能发布。

为了支持自定义验证和附加逻辑,我将初始代码从基于模板的表单切换为基于模型的表单;然而,一旦我启动重构的代码,我就会得到几个未找到指令注释错误,我不确定它们的含义。

可能我错过了一些明显的东西,但我是这里的新手。有人可以提出建议吗?你可以在这个 plunker 找到一个重现:http://plnkr.co/edit/v9Dj5j5opJmonxEeotcR http://plnkr.co/edit/v9Dj5j5opJmonxEeotcR。这是其中的一些基本代码:

a) 父组件:

@Component({
    selector: "word",
    directives: [FORM_DIRECTIVES, FORM_PROVIDERS, WordSense],
    templateUrl: `
<div>
    <form [ngFormModel]="wordForm"
          (ngSubmit)="onSubmit(wordForm.value)"
          role="form">

          <div class="form-group"
               [class.has-error]="!lemma.valid && lemma.touched">
            <label for="lemma">lemma</label>
            <input type="text" id="lemma"
                   maxlength="100" required spellcheck="false"
                   class="form-control"
                   placeholder="lemma"
                   [ngFormControl]="wordForm.controls['lemma']">
             <div *ngIf="lemma.hasError('required') && lemma.touched"
                  class="text-danger small">lemma required</div>
             <div *ngIf="lemma.hasError('lemmaValidator') && lemma.touched"
                  class="text-danger small">invalid lemma</div>
          </div>
            ...
          <div class="form-group">
            <table class="table table-bordered">
              <tbody>
              <tr *ngFor="#s of senses">
                <td>
                    <word-sense [sense]="s" [ranks]="ranks" [fields]="fields"></word-sense>
                </td>
              </tr>
              </tbody>
            </table>
          </div>
            ...              
          <button type="submit"
                  [ngClass]="{disabled: !wordForm.valid}"
                  class="btn btn-primary btn-sm">save</button>
     </form>
</div>
    `,
    inputs: [
        "word"
    ]
})
export class Word {
    private _word: IWordModel;

    public set word(value: IWordModel) {
        this._word = value;
        this.setFormValues();
    }
    public get word() {
        return this._word;
    }
    // ...

    // form
    public wordForm: ControlGroup;
    public lemma: Control;
    public language: Control;
    public class: Control;
    public ranks: IPair<number>[];
    public senses: ISenseViewModel[];
    public fields: IFieldModel[];

    constructor(private formBuilder:FormBuilder) {
        // ...
        this.senses = [
            this.createSense()
        ];
        // ...            
        // build the form
        this.wordForm = this.formBuilder.group({
            "lemma": ["", Validators.compose([Validators.required, LemmaValidator.isValidLemma])],
            "language": ["eng", Validators.required],
            "class": ["s.", Validators.required],
        });
        this.lemma = <Control> this.wordForm.controls["lemma"];
        this.language = <Control> this.wordForm.controls["language"];
        this.class = <Control> this.wordForm.controls["class"];
        // ...
    }
}

b) 子组件:

@Component({
    selector: "word-sense",
    directives: [FORM_DIRECTIVES],
    template: `
    <form class="form-inline" role="form" [ngFormModel]="senseForm">

    <div class="form-group" 
         [class.has-error]="!definitionCtl.valid">
        <input type="text" 
               class="form-control"
               placeholder="definition"
               [ngFormControl]="definitionCtl"
               [(ngModel)]="sense.definition">
    </div>

    <div class="form-group"
         [class.has-error]="!yearCtl.valid">
        <input type="number"
               class="form-control"
               placeholder="date"
               [ngFormControl]="yearCtl"
               [(ngModel)]="sense.year">
    </div>
    ...         
</form>
    `,
    inputs: [
        "sense",
        "ranks",
        "fields"
    ]
})
export class WordSense {
    // model being edited
    public sense: ISenseViewModel;
    // lookup data
    public ranks: IPair<number>[];
    public fields: IFieldModel[];
    public field: IFieldModel;
    // form
    public senseForm: ControlGroup;
    public definitionCtl: Control;
    public yearCtl: Control;
    public rankCtl: Control;
    public fieldsCtl: Control;

    constructor(private formBuilder: FormBuilder) {
        this.senseForm = this.formBuilder.group({
            "definition": ["", Validators.required],
            "year": [0, Validators.compose([Validators.required, YearValidator.isValidYear])],
            "rank": [{value: 2, label: "media"}, Validators.required],
            "fields": [""]
        });
        this.definitionCtl = <Control> this.senseForm.controls["definition"];
        this.yearCtl = <Control> this.senseForm.controls["year"];
        this.rankCtl = <Control> this.senseForm.controls["rank"];
        this.fieldsCtl = <Control> this.senseForm.controls["fields"];
    }
    // ...
}

为了有更多可读的错误,你可以更改 Angular2.min.js文件到.dev.js ones.

这样做,您现在出现以下错误:

在 FormBuilder 上找不到指令注释

事实上,问题在于你设置了FORM_PROVIDERS进入directives您的组件的属性。所以它尝试使用提供者作为指令,但他们不是......

@Component({
  selector: "word",
  directives: [FORM_DIRECTIVES, FORM_PROVIDERS, WordSense], <-----
  templateUrl: `
    <div>
    (...)
  `
})
export class ...

删除它应该可以解决您的问题:

@Component({
  selector: "word",
  directives: [FORM_DIRECTIVES, WordSense], <-----
  templateUrl: `
    <div>
    (...)
  `
})
export class ...

另一个问题是你使用templateUrl代替template为您Word成分:

@Component({
  selector: "word",
  directives: [FORM_DIRECTIVES,WordSense],
  templateUrl: ` <----------
  `
  (...)

你应该使用这个:

@Component({
  selector: "word",
  directives: [FORM_DIRECTIVES,WordSense],
  template: ` <----------
  `
  (...)

这是重构的 plunker:http://plnkr.co/edit/x0d5oiW1J9C2JrJG8NdT?p=preview http://plnkr.co/edit/x0d5oiW1J9C2JrJG8NdT?p=preview.

希望对你有帮助, 蒂埃里

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Angular2 beta:嵌套基于表单的父/子组件并从父级进行验证 的相关文章

随机推荐

  • 如何设置文本框输入长度

    使用VB6 在我的表单中使用文本框 我想限制文本框中的输入 因此最大值应为 6 用户最多应输入六个字符 否则应显示错误消息 Button1 click if Length textbox1 text gt 6 then enter only
  • 查找依赖于.NET 3.5 SP1的代码

    有没有办法运行某种代码分析来查找可以使用 NET 3 5 SP1 编译但不能使用 3 5 RTM 编译的代码 FxCop 适用于 SP1 引入的程序集 但对于仅调用新方法和属性的代码 它不会检测该用法 当然 您可以使用 fxcop 或 VS
  • 在 iPhone 中标记 CALayers

    我正在寻找一种通用方法 能够在层次结构中搜索唯一的 CALayer 而不必记住该层在层次结构中的位置 并使用 sublayer 和 superlayer 方法 我知道这对于 UIViews 是可能的 这使得翻转视图变得容易 但是 CALay
  • 如何解决此错误 VFY:无法解析虚拟方法

    我正在使用 android studio 2 0 上次我将 jdk 7 升级到 jdk 8 并对文件 gradle 进行了一些更改 但现在我收到此错误 E InstantRun Could not find slices in APK ab
  • 什么是比较合同?

    我的java代码抛出了以下异常 java lang IllegalArgumentException Comparison method violates its general contract 我研究了 StackOverflow 上的
  • 导入不适用于 tsconfig.json 中的 "module": "ESNEXT"

    我在服务器端有以下代码 import as express from express export class AppRouter private static instance express Router static getInsta
  • Flexbox 换行 - 最后一行的不同对齐方式

    我使用弹性框将两个项目与容器的左侧和右侧对齐 同时将它们垂直居中对齐 这是我想要实现的目标的一个非常简单的例子 HTML div class container div class first div div class second di
  • 如何判断 Delphi 应用程序是否“拥有”其控制台?

    Delphi 控制台应用程序可以从现有控制台窗口的命令行运行 并且可以通过双击其图标来运行 在后一种情况下 它将创建自己的控制台窗口 并在应用程序终止后将其关闭 如何判断我的控制台应用程序是否已创建自己的窗口 我想检测到这一点 以便我可以显
  • 使用 matplotlib + errorbar 进行动画

    我正在尝试根据这个例子制作动画 我的主要问题是我不知道如何将动画与错误栏连接起来 也许有人已经解决了 相似的东西 import numpy as np import matplotlib pyplot as plt import matpl
  • 将行分隔的 grep 结果放入数组中

    我有以下 grep 命令 echo v1 33 4 egrep o 0 9 1 3 返回 1 33 4 在 Bash 脚本中 我想将这些行分隔成一个数组 我尝试将它直接分配给一个变量并对其运行 for 循环 但循环内的回声仅产生第一个数字1
  • Eclipse 不允许从另一个工作区访问外部 jar 中的静态接口方法

    有两个 Eclipse 工作区 工作区A and 工作区B In 工作区A 有一个项目 其接口定义了公共静态方法 package workspacea public interface Foo public static String sa
  • 将自定义搜索字段添加到 DataTable 对象

    我需要将在页面上创建的字段添加到 DataTable 对象 尽管它们不是典型的参数 顺序 搜索 分页等 但它们可以与 DataTables 对象状态的其余部分一起保存和加载 JavaScript document ready functio
  • Android 设备选择器窗口目标栏中的橙色三角形是什么意思?

    当我使用 Eclipse 启动 Android 应用程序时 会出现通常的窗口 Android Device Chooser 我可以在这里选择要在哪个设备上运行我的应用程序 在目标列中 我的目标旁边会出现一个带有感叹号的橙色三角形 有点 警告
  • Numpy:从给定范围生成组合的有效方法

    我有一个 n 维数组 如下所示 np array 0 3 0 3 0 10 在此数组中 元素表示低值和高值 前任 0 3 指的是 0 1 2 3 我需要使用上面给出的范围生成所有值的组合 例如 我想要 0 0 0 0 0 1 0 1 0 3
  • 重新编码数值向量 R

    我有一个数字向量 让我们这样说 x lt rep 1 6 300 我想做的是重新编码向量 使 6 1 5 2 4 3 3 4 2 5 1 6 我不想从中创造一个因素 到目前为止 我尝试过的所有操作都因为顺序而给出了错误的计数 即 x x 6
  • Haskell 中一元运算符的前缀形式

    In GHCi 前奏 gt 3 2 5 前奏 gt 3 2 6 前奏 gt 3 20 66666666666666666 前奏 gt 3 2没有 Num t gt t1 的实例由字面意思产生的3 at
  • 使用 FILTERXML 将字符串解析为表

    这与此有关question https stackoverflow com questions 69045317 how to calculate backplane throughput given an arbitrary list o
  • 数组的 setter 和 getter

    我是 Java 新手 我需要一些澄清如何解决问题 我有课Epicycle 定义如下 public class Ts epicycle private double epoch private double tle new double 10
  • xmpphp XMPP,从 php 脚本发送消息

    你好 我有一个 jabberserver 我希望能够从 php 脚本向用户推送消息 F x 如果我从浏览器调用 script php 它会向用户发送一条消息 我已经尝试过 jaxl 和 xmpphp 这两个 xmp 框架 但我无法让它工作
  • Angular2 beta:嵌套基于表单的父/子组件并从父级进行验证

    我正在尝试在 Angular2 Plunker 中带有 TS 的 beta 0 中实现一个具有 2 个嵌套表单的场景 每个表单由一个组件表示 父组件是Word 它代表假字典中的单词 子组件是WordSense s 每个都代表父词的一种含义