将 "provideForms()" 添加到我的 main.ts 后,模板驱动表单出现问题
Issue with template-driven forms after adding "provideForms()" to my main.ts
我最近开始迁移到模型驱动表单而不是模板驱动表单。
我不得不在我的 main.ts
中添加一个 provideForms(),
。
从那时起,我所有的模板驱动表单都会引发异常,例如:
Reference "#firstNameForm" is defined several times
完整消息如下:
browser_adapter.ts:82 EXCEPTION: Error: Uncaught (in promise): Template parse errors:
Reference "#firstNameForm" is defined several times ("<h4>{{'FIRST_NAME_FORM.TITLE' | translate}}</h4>
<form (ngSubmit)="updateFirstName(firstNameForm)" [ERROR ->]#firstNameForm="ngForm" novalidate>
<div class="form-group" [ngClass]="getCssClasses(firstNameFor"): UserAccountFirstNameComponent@1:50BrowserDomAdapter.logError @ browser_adapter.ts:82BrowserDomAdapter.logGroup @ browser_adapter.ts:93ExceptionHandler.call @ exception_handler.ts:58(anonymous function) @ application_ref.ts:374schedulerFn @ async.ts:148SafeSubscriber.__tryOrUnsub @ Subscriber.ts:240SafeSubscriber.next @ Subscriber.ts:192Subscriber._next @ Subscriber.ts:133Subscriber.next @ Subscriber.ts:93Subject._finalNext @ Subject.ts:154Subject._next @ Subject.ts:144Subject.next @ Subject.ts:90EventEmitter.emit @ async.ts:133onError @ ng_zone.ts:142onHandleError @ ng_zone_impl.ts:95ZoneDelegate.handleError @ zone.js:327Zone.runGuarded @ zone.js:233_loop_1 @ zone.js:487drainMicroTaskQueue @ zone.js:494ZoneTask.invoke @ zone.js:426
browser_adapter.ts:82 STACKTRACE:BrowserDomAdapter.logError @ browser_adapter.ts:82ExceptionHandler.call @ exception_handler.ts:61(anonymous function) @ application_ref.ts:374schedulerFn @ async.ts:148SafeSubscriber.__tryOrUnsub @ Subscriber.ts:240SafeSubscriber.next @ Subscriber.ts:192Subscriber._next @ Subscriber.ts:133Subscriber.next @ Subscriber.ts:93Subject._finalNext @ Subject.ts:154Subject._next @ Subject.ts:144Subject.next @ Subject.ts:90EventEmitter.emit @ async.ts:133onError @ ng_zone.ts:142onHandleError @ ng_zone_impl.ts:95ZoneDelegate.handleError @ zone.js:327Zone.runGuarded @ zone.js:233_loop_1 @ zone.js:487drainMicroTaskQueue @ zone.js:494ZoneTask.invoke @ zone.js:426
组件文件如下:
import {Component, OnInit} from "@angular/core";
import {ControlGroup, NgClass} from "@angular/common";
import {ROUTER_DIRECTIVES, Router} from "@angular/router";
import {TranslatePipe} from "ng2-translate/ng2-translate";
import {UserAccountService} from "../useraccount.service";
import {AppConstants} from "../../shared/app-constants";
import {StylingService} from "../../shared/services/styling.service";
import {UserAccount} from "../../shared/models/useraccount.model";
@Component({
moduleId: module.id,
templateUrl: 'useraccount-firstname.component.html',
directives: [ROUTER_DIRECTIVES, NgClass],
pipes: [TranslatePipe]
})
export class UserAccountFirstNameComponent implements OnInit {
//TODO (code review): user account's first name is updated in real time when user types into the first name form, before even they have validated the form. How can I avoid that?
currentUserAccount:UserAccount;
submitted:boolean = false;
FIRST_NAME_PATTERN = AppConstants.FIRST_NAME_PATTERN;
getCssClasses = this.stylingService.getCssClasses;
isSuccessFeedback = this.stylingService.isSuccessFeedback;
isErrorFeedback = this.stylingService.isErrorFeedback;
constructor(private userAccountService:UserAccountService,
private stylingService:StylingService,
private router:Router) {
}
ngOnInit() {
this.userAccountService.currentUserAccount$.subscribe({
next: (param)=>this.currentUserAccount = param
});
}
updateFirstName(firstNameForm:ControlGroup) {
this.submitted = true;
if (firstNameForm.valid) {
this.userAccountService.updateFirstName(this.currentUserAccount);
this.router.navigate(['/dashboard/useraccount']);
}
}
}
组件模板如下:
<h4>{{'FIRST_NAME_FORM.TITLE' | translate}}</h4>
<form (ngSubmit)="updateFirstName(firstNameForm)" #firstNameForm="ngForm" novalidate>
<div class="form-group" [ngClass]="getCssClasses(firstNameForm, firstName)">
<div class="input-group">
<span class="input-group-addon">
<span class="glyphicon icon-account" aria-hidden="true"></span>
</span>
<input type="text"
ngControl="firstName"
#firstName="ngForm"
required
minlength="2"
maxlength="35"
pattern_="FIRST_NAME_PATTERN"
[ngModel]="currentUserAccount?.firstName"
(ngModelChange)="currentUserAccount ? currentUserAccount.firstName = $event : null"
placeholder="{{'FIRST_NAME_FORM.NEW_FIRST_NAME'| translate }}"
class="form-control"/>
</div>
<span *ngIf="isSuccessFeedback(firstNameForm, firstName)" class="form-control-feedback" aria-hidden="true">
<span class="glyphicon icon-accept" aria-hidden="true"></span>
</span>
<span *ngIf="isErrorFeedback(firstNameForm, firstName)" class="form-control-feedback" aria-hidden="true">
<span class="glyphicon icon-close" aria-hidden="true"></span>
</span>
<div [hidden]="firstName.valid || !submitted">
<div *ngIf="firstName?.errors?.required" class="control-label">{{'FIRST_NAME_FORM.REQUIRED'| translate}}</div>
<div *ngIf="firstName?.errors?.minlength" class="control-label">{{'FIRST_NAME_FORM.MIN_LENGTH'| translate}}</div>
<div *ngIf="firstName?.errors?.maxlength" class="control-label">{{'FIRST_NAME_FORM.MAX_LENGTH'| translate}}</div>
<div *ngIf="firstName?.errors?.pattern" class="control-label">{{'FIRST_NAME_FORM.PATTERN'| translate}}</div>
</div>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary pull-right" [disabled]="buttonDisabled">{{'FIRST_NAME_FORM.SUBMIT'| translate}}</button>
<a [routerLink]="['/dashboard/useraccount']" class="btn btn-link pull-right text-right">{{'FORM_CANCEL' | translate}}</a>
</div>
</form>
有人可以帮忙吗?
您似乎在混合使用新旧形式。
如果你使用
bootstrap(AppComponent, [
disableDeprecatedForms()
provideForms()
])
不要从
导入表单内容
import {ControlGroup, ...} from "@angular/common";
而是从 @angular/forms
导入它
另见
我最近开始迁移到模型驱动表单而不是模板驱动表单。
我不得不在我的 main.ts
中添加一个 provideForms(),
。
从那时起,我所有的模板驱动表单都会引发异常,例如:
Reference "#firstNameForm" is defined several times
完整消息如下:
browser_adapter.ts:82 EXCEPTION: Error: Uncaught (in promise): Template parse errors:
Reference "#firstNameForm" is defined several times ("<h4>{{'FIRST_NAME_FORM.TITLE' | translate}}</h4>
<form (ngSubmit)="updateFirstName(firstNameForm)" [ERROR ->]#firstNameForm="ngForm" novalidate>
<div class="form-group" [ngClass]="getCssClasses(firstNameFor"): UserAccountFirstNameComponent@1:50BrowserDomAdapter.logError @ browser_adapter.ts:82BrowserDomAdapter.logGroup @ browser_adapter.ts:93ExceptionHandler.call @ exception_handler.ts:58(anonymous function) @ application_ref.ts:374schedulerFn @ async.ts:148SafeSubscriber.__tryOrUnsub @ Subscriber.ts:240SafeSubscriber.next @ Subscriber.ts:192Subscriber._next @ Subscriber.ts:133Subscriber.next @ Subscriber.ts:93Subject._finalNext @ Subject.ts:154Subject._next @ Subject.ts:144Subject.next @ Subject.ts:90EventEmitter.emit @ async.ts:133onError @ ng_zone.ts:142onHandleError @ ng_zone_impl.ts:95ZoneDelegate.handleError @ zone.js:327Zone.runGuarded @ zone.js:233_loop_1 @ zone.js:487drainMicroTaskQueue @ zone.js:494ZoneTask.invoke @ zone.js:426
browser_adapter.ts:82 STACKTRACE:BrowserDomAdapter.logError @ browser_adapter.ts:82ExceptionHandler.call @ exception_handler.ts:61(anonymous function) @ application_ref.ts:374schedulerFn @ async.ts:148SafeSubscriber.__tryOrUnsub @ Subscriber.ts:240SafeSubscriber.next @ Subscriber.ts:192Subscriber._next @ Subscriber.ts:133Subscriber.next @ Subscriber.ts:93Subject._finalNext @ Subject.ts:154Subject._next @ Subject.ts:144Subject.next @ Subject.ts:90EventEmitter.emit @ async.ts:133onError @ ng_zone.ts:142onHandleError @ ng_zone_impl.ts:95ZoneDelegate.handleError @ zone.js:327Zone.runGuarded @ zone.js:233_loop_1 @ zone.js:487drainMicroTaskQueue @ zone.js:494ZoneTask.invoke @ zone.js:426
组件文件如下:
import {Component, OnInit} from "@angular/core";
import {ControlGroup, NgClass} from "@angular/common";
import {ROUTER_DIRECTIVES, Router} from "@angular/router";
import {TranslatePipe} from "ng2-translate/ng2-translate";
import {UserAccountService} from "../useraccount.service";
import {AppConstants} from "../../shared/app-constants";
import {StylingService} from "../../shared/services/styling.service";
import {UserAccount} from "../../shared/models/useraccount.model";
@Component({
moduleId: module.id,
templateUrl: 'useraccount-firstname.component.html',
directives: [ROUTER_DIRECTIVES, NgClass],
pipes: [TranslatePipe]
})
export class UserAccountFirstNameComponent implements OnInit {
//TODO (code review): user account's first name is updated in real time when user types into the first name form, before even they have validated the form. How can I avoid that?
currentUserAccount:UserAccount;
submitted:boolean = false;
FIRST_NAME_PATTERN = AppConstants.FIRST_NAME_PATTERN;
getCssClasses = this.stylingService.getCssClasses;
isSuccessFeedback = this.stylingService.isSuccessFeedback;
isErrorFeedback = this.stylingService.isErrorFeedback;
constructor(private userAccountService:UserAccountService,
private stylingService:StylingService,
private router:Router) {
}
ngOnInit() {
this.userAccountService.currentUserAccount$.subscribe({
next: (param)=>this.currentUserAccount = param
});
}
updateFirstName(firstNameForm:ControlGroup) {
this.submitted = true;
if (firstNameForm.valid) {
this.userAccountService.updateFirstName(this.currentUserAccount);
this.router.navigate(['/dashboard/useraccount']);
}
}
}
组件模板如下:
<h4>{{'FIRST_NAME_FORM.TITLE' | translate}}</h4>
<form (ngSubmit)="updateFirstName(firstNameForm)" #firstNameForm="ngForm" novalidate>
<div class="form-group" [ngClass]="getCssClasses(firstNameForm, firstName)">
<div class="input-group">
<span class="input-group-addon">
<span class="glyphicon icon-account" aria-hidden="true"></span>
</span>
<input type="text"
ngControl="firstName"
#firstName="ngForm"
required
minlength="2"
maxlength="35"
pattern_="FIRST_NAME_PATTERN"
[ngModel]="currentUserAccount?.firstName"
(ngModelChange)="currentUserAccount ? currentUserAccount.firstName = $event : null"
placeholder="{{'FIRST_NAME_FORM.NEW_FIRST_NAME'| translate }}"
class="form-control"/>
</div>
<span *ngIf="isSuccessFeedback(firstNameForm, firstName)" class="form-control-feedback" aria-hidden="true">
<span class="glyphicon icon-accept" aria-hidden="true"></span>
</span>
<span *ngIf="isErrorFeedback(firstNameForm, firstName)" class="form-control-feedback" aria-hidden="true">
<span class="glyphicon icon-close" aria-hidden="true"></span>
</span>
<div [hidden]="firstName.valid || !submitted">
<div *ngIf="firstName?.errors?.required" class="control-label">{{'FIRST_NAME_FORM.REQUIRED'| translate}}</div>
<div *ngIf="firstName?.errors?.minlength" class="control-label">{{'FIRST_NAME_FORM.MIN_LENGTH'| translate}}</div>
<div *ngIf="firstName?.errors?.maxlength" class="control-label">{{'FIRST_NAME_FORM.MAX_LENGTH'| translate}}</div>
<div *ngIf="firstName?.errors?.pattern" class="control-label">{{'FIRST_NAME_FORM.PATTERN'| translate}}</div>
</div>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary pull-right" [disabled]="buttonDisabled">{{'FIRST_NAME_FORM.SUBMIT'| translate}}</button>
<a [routerLink]="['/dashboard/useraccount']" class="btn btn-link pull-right text-right">{{'FORM_CANCEL' | translate}}</a>
</div>
</form>
有人可以帮忙吗?
您似乎在混合使用新旧形式。
如果你使用
bootstrap(AppComponent, [
disableDeprecatedForms()
provideForms()
])
不要从
导入表单内容import {ControlGroup, ...} from "@angular/common";
而是从 @angular/forms
另见