关于 angular 中模板驱动表单中 ngForm 和 ngModel 的概念
About concept of ngForm and ngModel in template driven forms in angular
你好,我最近涉足 angular 和离子开发。
我理解插值和属性绑定是将数据从class传递给模板,插值只支持字符串,而属性绑定支持所有类型。
事件绑定用于将数据从模板传递到 class。
使用foll实现了双向绑定。 4种方式:
- 使用 ngModel 香蕉语法:
<input [(ngModel)]="username">
<p>Hello {{username}}!</p>
- 没有香蕉语法的 NgModel:
<input [ngModel]="username" (ngModelChange)="username = $event">
<p>Hello {{username}}!</p>
- 没有 ngModel:
<input [value]="username" (input)="username = $event.target.value">
<p>Hello {{username}}!</p>
或
<input [value]="username" (input)="username = varTest.value" #varTest>
<p>Hello {{username}}!</p>
- 只要我们实现适当的功能,我们就可以实现自定义双向绑定(没有 ngModel):
<custom-counter [(counter)]="someValue"></custom-counter>
<p>counterValue = {{someValue}}</p>
我们还有一个模板引用变量的概念。当您在输入字段上声明它时,可以使用插值在模板中访问字段的值。此外,如果将 ngModel 分配给模板引用变量.. #varTref="ngModel",则可以使用插值在模板中访问元素的各种属性,如验证、脏、原始、触摸、未触摸。所有这些都可以传递给代码 class 文件,方法是将模板引用变量传递给按钮单击事件,或者我们可以使用 ViewChild 概念。
我的问题是关于表单(模板驱动表单)中的 ngForms 和 ngModel 概念:
我们用<form #f="ngForm".....
然后在每个输入元素中,我们使用带有名称的 ngModel,这使得它可以作为 forms.value.fieldname 的 属性 访问。
仅仅通过使用模板引用变量,然后将其传递给按钮单击事件,从而访问代码中的表单元素,难道不能实现同样的事情吗?那为什么一定要用到ngForm的概念呢?
在元素级别我们使用 ngModel。这与属性绑定或事件绑定相同吗?还是只是让#f 可以访问该元素?我们也可以使用模板引用变量来实现同样的效果,不是吗?为了实现双向绑定,我们在这里也使用香蕉语法,那么仅在每个元素级别使用关键字 ngModel 真正用于模板驱动形式的目的是什么?
使用 [(ngModel)]=varName 和写 [(ngModel)] name=varName 一样吗?
我需要澄清一下。谢谢。
是的,这些概念一开始可能会令人困惑。但是您在上面指定的有关双向绑定的某些信息不正确:
双向绑定
[(ngModel)]="lastName"
对组件 属性 的任何修改都显示在模板中,模板中的任何更改都在组件 属性 中设置。这最常用于输入框和模板驱动的表单。
以上是这个的 "short-cut" 版本:
<input [ngModel]="lastName" (ngModelChange)="lastName = $event">
一个way/property绑定
[ngModel]="lastName"
UI 与组件 属性 的值保持同步。这个类似于插值:{{lastName}}
一次性绑定
ngModel="lastName"
只绑定组件的初始值属性,值改变时不会改变
模板引用变量
#lastNameVar="ngModel" /* for a form model element eg input element*/
#f="ngForm" /* for the form itself */
模板引用变量的主要目的是提供对模板中项目的引用。您不需要将它添加到模板驱动表单上的每个 输入元素,只需添加到您想要访问的那些。
例如:
<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>
注意上面如何将模板引用变量设置为 #lastName
,然后使用它来设置样式(使用 [ngClass]
)并检查错误集合以显示适当的错误消息。
或者对于您的表单示例,您可以检查表单状态以禁用“保存”按钮,例如:
<button class="btn btn-primary"
type="submit"
[disabled]="!f.valid">
Save
</button>
如果您不需要访问模板中的表单状态,则不需要模板引用变量。
您还可以将表单的模板引用变量传递到组件中以访问表单值或状态:
在模板中:
<form novalidate
(ngSubmit)="save(signupForm)"
#signupForm="ngForm">
在组件中:
save(customerForm: NgForm) {
console.log('Saved: ' + JSON.stringify(customerForm.value));
}
您可以改为传入每个单独控件的模板引用变量,但为什么呢?随着时间的推移添加控件,您必须记住始终将其添加到方法调用中。而且您必须检查每个控件的状态,而不仅仅是表单的整体状态。简单地将引用传递给表单就很多了easier/better/clearer。
<form novalidate
(ngSubmit)="save(lastName, firstName, phone, email)">
你好,我最近涉足 angular 和离子开发。
我理解插值和属性绑定是将数据从class传递给模板,插值只支持字符串,而属性绑定支持所有类型。
事件绑定用于将数据从模板传递到 class。
使用foll实现了双向绑定。 4种方式:
- 使用 ngModel 香蕉语法:
<input [(ngModel)]="username"> <p>Hello {{username}}!</p>
- 没有香蕉语法的 NgModel:
<input [ngModel]="username" (ngModelChange)="username = $event"> <p>Hello {{username}}!</p>
- 没有 ngModel:
<input [value]="username" (input)="username = $event.target.value"> <p>Hello {{username}}!</p>
或
<input [value]="username" (input)="username = varTest.value" #varTest> <p>Hello {{username}}!</p>
- 只要我们实现适当的功能,我们就可以实现自定义双向绑定(没有 ngModel):
<custom-counter [(counter)]="someValue"></custom-counter> <p>counterValue = {{someValue}}</p>
我们还有一个模板引用变量的概念。当您在输入字段上声明它时,可以使用插值在模板中访问字段的值。此外,如果将 ngModel 分配给模板引用变量.. #varTref="ngModel",则可以使用插值在模板中访问元素的各种属性,如验证、脏、原始、触摸、未触摸。所有这些都可以传递给代码 class 文件,方法是将模板引用变量传递给按钮单击事件,或者我们可以使用 ViewChild 概念。
我的问题是关于表单(模板驱动表单)中的 ngForms 和 ngModel 概念:
我们用
<form #f="ngForm".....
然后在每个输入元素中,我们使用带有名称的 ngModel,这使得它可以作为 forms.value.fieldname 的 属性 访问。 仅仅通过使用模板引用变量,然后将其传递给按钮单击事件,从而访问代码中的表单元素,难道不能实现同样的事情吗?那为什么一定要用到ngForm的概念呢?在元素级别我们使用 ngModel。这与属性绑定或事件绑定相同吗?还是只是让#f 可以访问该元素?我们也可以使用模板引用变量来实现同样的效果,不是吗?为了实现双向绑定,我们在这里也使用香蕉语法,那么仅在每个元素级别使用关键字 ngModel 真正用于模板驱动形式的目的是什么?
使用 [(ngModel)]=varName 和写 [(ngModel)] name=varName 一样吗?
我需要澄清一下。谢谢。
是的,这些概念一开始可能会令人困惑。但是您在上面指定的有关双向绑定的某些信息不正确:
双向绑定
[(ngModel)]="lastName"
对组件 属性 的任何修改都显示在模板中,模板中的任何更改都在组件 属性 中设置。这最常用于输入框和模板驱动的表单。
以上是这个的 "short-cut" 版本:
<input [ngModel]="lastName" (ngModelChange)="lastName = $event">
一个way/property绑定
[ngModel]="lastName"
UI 与组件 属性 的值保持同步。这个类似于插值:{{lastName}}
一次性绑定
ngModel="lastName"
只绑定组件的初始值属性,值改变时不会改变
模板引用变量
#lastNameVar="ngModel" /* for a form model element eg input element*/
#f="ngForm" /* for the form itself */
模板引用变量的主要目的是提供对模板中项目的引用。您不需要将它添加到模板驱动表单上的每个 输入元素,只需添加到您想要访问的那些。
例如:
<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>
注意上面如何将模板引用变量设置为 #lastName
,然后使用它来设置样式(使用 [ngClass]
)并检查错误集合以显示适当的错误消息。
或者对于您的表单示例,您可以检查表单状态以禁用“保存”按钮,例如:
<button class="btn btn-primary"
type="submit"
[disabled]="!f.valid">
Save
</button>
如果您不需要访问模板中的表单状态,则不需要模板引用变量。
您还可以将表单的模板引用变量传递到组件中以访问表单值或状态:
在模板中:
<form novalidate
(ngSubmit)="save(signupForm)"
#signupForm="ngForm">
在组件中:
save(customerForm: NgForm) {
console.log('Saved: ' + JSON.stringify(customerForm.value));
}
您可以改为传入每个单独控件的模板引用变量,但为什么呢?随着时间的推移添加控件,您必须记住始终将其添加到方法调用中。而且您必须检查每个控件的状态,而不仅仅是表单的整体状态。简单地将引用传递给表单就很多了easier/better/clearer。
<form novalidate
(ngSubmit)="save(lastName, firstName, phone, email)">