关于Angular模板驱动形式中的ngForm和ngModel的概念

var*_*ble 1 angular-ngmodel angular

您好,我最近冒险进行角和离子的开发。

我知道插值和属性绑定是将数据从类传递到模板,并且插值仅支持字符串,而属性绑定支持所有类型。

事件绑定用于将数据从模板传递到类。

使用foll实现两种方式的绑定。4种方式:

  1. 使用ngModel banana语法:
<input [(ngModel)]="username">
<p>Hello {{username}}!</p>
Run Code Online (Sandbox Code Playgroud)
  1. 没有香蕉语法的NgModel:
<input [ngModel]="username" (ngModelChange)="username = $event">
<p>Hello {{username}}!</p>
Run Code Online (Sandbox Code Playgroud)
  1. 没有ngModel:
<input [value]="username" (input)="username = $event.target.value">
<p>Hello {{username}}!</p>
Run Code Online (Sandbox Code Playgroud)

要么

<input [value]="username" (input)="username = varTest.value" #varTest>
<p>Hello {{username}}!</p>
Run Code Online (Sandbox Code Playgroud)
  1. 只要实现适当的功能,我们就可以实现自定义的双向绑定(没有ngModel):
<custom-counter [(counter)]="someValue"></custom-counter>
<p>counterValue = {{someValue}}</p>
Run Code Online (Sandbox Code Playgroud)

我们也有模板引用变量的概念。在输入字段上声明时,可以使用插值在模板中访问字段的值。同样,如果将ngModel分配给模板ref变量。所有这些都可以通过将模板ref变量传递到例如按钮单击事件中来传递到代码类文件,或者我们可以利用ViewChild概念。

我的问题是关于表单(模板驱动的表单)情况下的ngForms和ngModel概念:

  1. 我们使用<form #f="ngForm"..... ,然后在每个输入元素中使用带有名称的ngModel,这使得它可以作为form.value.fieldname的属性进行访问。仅仅通过使用模板引用变量,然后将其传递给按钮单击事件,从而可以访问代码中的表单元素,是否可以实现同一目的?那为什么我们必须使用ngForm概念呢?

  2. 在元素级别,我们使用ngModel。这与属性绑定或事件绑定相同吗?还是仅仅是让#f可以访问该元素?我们还可以使用模板引用变量来实现相同的功能吗?为了实现双向绑定,我们在这里也使用了banana语法,那么仅在每个元素级别使用关键字ngModel真正以模板驱动形式起作用是什么目的?

  3. 使用[[ngModel)] = varName与编写[[ngModel)] name = varName一样吗?

请在此我需要一些澄清。谢谢。

Deb*_*ahK 6

是的,这些概念起初可能会令人困惑。但是您上面指定的有关双向绑定的某些信息不正确:

双向装订

[(ngModel)]="lastName"

对组件属性的任何修改都显示在模板中,而模板中的任何更改都在组件属性中设置。这最常用于输入框和模板驱动的表单。

上面是这个的“捷径”版本:

<input [ngModel]="lastName" (ngModelChange)="lastName = $event">

一种方式/属性绑定

[ngModel]="lastName"

UI与component属性的值保持同步。这类似于插值:{{lastName}}

一次绑定

ngModel="lastName"

仅绑定组件属性的初始值,如果值更改,则不会更改。

模板参考变量

#lastNameVar="ngModel"    /* for a form model element eg input element*/
#f="ngForm"               /* for the form itself */
Run Code Online (Sandbox Code Playgroud)

模板引用变量的主要目的是提供对模板中项目的引用。您不需要将其添加到模板驱动表单上的每个输入元素,只需要将它们添加到模板即可。

例如:

  <div class="form-group row mb-2">
    <label class="col-md-2 col-form-label"
           for="lastNameId">Last Name</label>
    <div class="col-md-8">
      <input class="form-control"
             id="lastNameId"
             type="text"
             placeholder="Last Name (required)"
             required
             maxlength="50"
             [(ngModel)]="customer.lastName"
             name="lastName"
             #lastNameVar="ngModel"
             [ngClass]="{'is-invalid': (lastNameVar.touched || lastNameVar.dirty) && !lastNameVar.valid }" />
      <span class="invalid-feedback">
        <span *ngIf="lastNameVar.errors?.required">
          Please enter your last name.
        </span>
        <span *ngIf="lastNameVar.errors?.maxlength">
          The last name must be less than 50 characters.
        </span>
      </span>
    </div>
  </div>
Run Code Online (Sandbox Code Playgroud)

请注意,上面是如何将模板引用变量设置为#lastName,然后使用它来设置样式(带有[ngClass])并检查错误集合以显示适当的错误消息。

或以表单的示例为例,您可以检查表单状态以禁用“保存”按钮,例如:

      <button class="btn btn-primary"
              type="submit"
              [disabled]="!f.valid">
        Save
      </button>
Run Code Online (Sandbox Code Playgroud)

如果不需要访问模板中表单的状态,则不需要模板引用变量。

您还可以将表单的模板引用变量传递到组件中以访问表单的值或状态:

在模板中:

<form novalidate
      (ngSubmit)="save(signupForm)"
      #signupForm="ngForm">
Run Code Online (Sandbox Code Playgroud)

在组件中:

  save(customerForm: NgForm) {
    console.log('Saved: ' + JSON.stringify(customerForm.value));
  }
Run Code Online (Sandbox Code Playgroud)

可以改为传入每个控件的模板引用变量,但是为什么呢?随着时间的推移添加控件,您必须记住始终将其添加到方法调用中。而且您必须检查每个控件的状态,而不仅仅是表单的整体状态。简单地将引用传递给表单会更容易/更好/更清晰。

<form novalidate
      (ngSubmit)="save(lastName, firstName, phone, email)">
Run Code Online (Sandbox Code Playgroud)