Angular 创建可重用的角度数据输入(邮寄地址)组件
我正在创建一个Angular 11应用程序,其中有3个不同的邮件地址要输入。我想我不知道该做什么,但我想我不知道。我正在获取具有非唯一id警告的元素。第一次尝试失败后,我学习了单组件角度模块。我正在我的参考应用程序上尝试一个概念诈骗组件 我收到以下运行时警告:Angular 创建可重用的角度数据输入(邮寄地址)组件,angular,typescript,input,reusability,Angular,Typescript,Input,Reusability,我正在创建一个Angular 11应用程序,其中有3个不同的邮件地址要输入。我想我不知道该做什么,但我想我不知道。我正在获取具有非唯一id警告的元素。第一次尝试失败后,我学习了单组件角度模块。我正在我的参考应用程序上尝试一个概念诈骗组件 我收到以下运行时警告: [DOM] Found 2 elements with non-unique id #Address2: [DOM] Found 2 elements with non-unique id #Address1: 我的概念地址组件如下所示
[DOM] Found 2 elements with non-unique id #Address2:
[DOM] Found 2 elements with non-unique id #Address1:
我的概念地址组件如下所示:
import { Component, OnInit, Input, Output, NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { CommonModule } from '@angular/common';
//
@Component({
selector: 'app-address',
template: `
<label for='Address1'>{{addressLabel}}</label>
<input type='text' id='Address1' name='Address1' required maxlength='50' class='nsg-input-wide'
#Address1='ngModel' [(ngModel)]='address1' (ngModelChange)='onDataChange( $event )'
placeholder='Address 1...' [disabled]='disabled' />
<div *ngIf='Address1.invalid && Address1.touched' style='color: red;'>
'Address 1' is required.
</div>
<label for='Address2'>Address 2:</label>
<input type='text' id='Address2' name='Address2' required maxlength='50' class='nsg-input-wide'
#Address2='ngModel' [(ngModel)]='address2' (ngModelChange)='onDataChange( $event )'
placeholder='Address 2...' [disabled]='disabled' />
`
})
export class AddressComponent implements OnInit {
@Input() disabled: boolean = true;
@Input() addressLabel: string = 'Address:';
@Input() address1: string = '';
@Input() address2: string = '';
//
constructor() { }
ngOnInit(): void { }
onDataChange( event: any ): boolean {
// this.onFormChanged.emit( event );
return false;
}
}
@NgModule({
declarations: [ AddressComponent ],
imports: [
CommonModule,
FormsModule
],
exports: [ AddressComponent ]
})
export class AddressModule { }
...
<app-address
[disabled]='addressDisabled'
[addressLabel]='addressLabel_1'
[address1]='address1_1'
[address2]='address2_1'>
</app-address>
<br />
<app-address
[disabled]='addressDisabled'
[addressLabel]='addressLabel_2'
[address1]='address1_2'
[address2]='address2_2'>
</app-address>
...
...
addressDisabled: boolean = false;
addressLabel_1: string = 'Office Address:';
address1_1: string = 'Address 1';
address2_1: string = 'Address 2';
addressLabel_2: string = 'Remit Address:';
address1_2: string = 'Address 1 2';
address2_2: string = 'Address 2 2';
...
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { CommonModule } from '@angular/common';
//
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { AddressComponent, AddressModule } from './scam/address/address.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
FormsModule,
CommonModule,
AppRoutingModule,
AddressModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
// ===========================================================================
// File: address.component.ts
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
//
import { IAddress, Address } from '../../admin/classes/address';
//
@Component({
selector: 'app-address',
template: `
<div class='row form-group' [class.has-error]='Address1.invalid && Address1.touched && validation'>
<div class='col-lg-3 col-md-4 col-sm-12 nsg-primary-color nsg-text-right'><label for='Address1{{uniquePostfix}}'>{{addressLabel}}</label></div>
<div class='col-lg-8 col-md-7 col-sm-12'>
<input type='text' id='Address1{{uniquePostfix}}' name='Address1{{uniquePostfix}}' required maxlength='50' class='nsg-input-wide'
#Address1='ngModel' [(ngModel)]='model.Address1' (ngModelChange)='onDataChange( $event )'
placeholder='Address 1...' [disabled]='disabled' />
</div>
<div class='col-lg-1 col-md-1 col-sm-12 nsg-alert-color' *ngIf='Address1.invalid && Address1.touched && validation'>Required</div>
</div>
<div class='row form-group'>
<div class='col-lg-3 col-md-4 col-sm-12 nsg-primary-color nsg-text-right'><label for='Address2{{uniquePostfix}}'> </label></div>
<div class='col-lg-8 col-md-7 col-sm-12'>
<input type='text' id='Address2{{uniquePostfix}}' name='Address2{{uniquePostfix}}' required maxlength='50' class='nsg-input-wide'
#Address2='ngModel' [(ngModel)]='model.Address2' (ngModelChange)='onDataChange( $event )'
placeholder='Address 2...' [disabled]='disabled' />
</div>
</div>
<div class='row form-group' [class.has-error]='(City.invalid && City.touched && validation) || (State.invalid && State.touched && validation) || (Zip.invalid && Zip.touched && validation) || (Country.invalid && Country.touched && validation)'>
<div class='col-lg-3 col-md-4 col-sm-12 nsg-primary-color nsg-text-right'><label for='City{{uniquePostfix}}'>{{cityStateLabel}}</label></div>
<div class='col-lg-auto col-md-auto col-sm-12'>
<input type='text' id='City{{uniquePostfix}}' name='City{{uniquePostfix}}' required maxlength='50' size='20'
#City='ngModel' [(ngModel)]='model.City' (ngModelChange)='onDataChange( $event )'
placeholder='City...' [disabled]='disabled' />
<input type='text' id='State{{uniquePostfix}}' name='State{{uniquePostfix}}' required maxlength='3' size='2'
#State='ngModel' [(ngModel)]='model.State' (ngModelChange)='onDataChange( $event )'
placeholder='State...' [disabled]='disabled' />
<input type='text' id='Zip{{uniquePostfix}}' name='Zip{{uniquePostfix}}' required maxlength='12' size='11'
#Zip='ngModel' [(ngModel)]='model.Zip' (ngModelChange)='onDataChange( $event )'
placeholder='Zip...' [disabled]='disabled' />
<input type='text' id='Country{{uniquePostfix}}' name='Country{{uniquePostfix}}' required maxlength='3' size='2'
#Country='ngModel' [(ngModel)]='model.Country' (ngModelChange)='onDataChange( $event )'
placeholder='Country...' [disabled]='disabled' />
</div>
<div class='col-lg-2 col-md-3 col-sm-12 nsg-alert-color' *ngIf='City.invalid || State.invalid || Zip.invalid || Country.invalid'>
<div *ngIf='City.invalid && City.touched && validation'>City Req.</div>
<div *ngIf='State.invalid && State.touched && validation'>State Req.</div>
<div *ngIf='Zip.invalid && Zip.touched && validation'>Zip Req.</div>
<div *ngIf='Country.invalid && Country.touched && validation'>Ctry Req.</div>
</div>
</div>
`
})
export class AddressComponent implements OnInit {
@Input() disabled: boolean = true;
@Input() addressLabel: string = 'Address:';
@Input() cityStateLabel: string = 'City/State/Zip:';
@Input() uniquePostfix: string = '';
@Input() validation: boolean = true;
model: IAddress;
@Input() set address( address: IAddress ) {
this.model = address;
}
get address(): IAddress { return this.model; }
@Output() onAddressChanged = new EventEmitter<boolean>();
//
constructor() {
// static constructor method
this.model = Address.empty( );
}
/*
** Component initialization, place all long running
** initializations here.
*/
ngOnInit(): void {
}
/*
** Events
** * flag that the form is dirty.
*/
onDataChange( event: any ): boolean {
this.onAddressChanged.emit( true );
return false;
}
//
}
// ===========================================================================
<app-address
[disabled]='!editable'
[uniquePostfix]='companyUniquePostfix'
[address]='model.CompanyAddress'
(onAddressChanged)='onFormChanged( $event )'>
</app-address>
<app-address
[disabled]='!editable'
[addressLabel]='remitAddressLabel'
[uniquePostfix]='remitUniquePostfix'
[validation]='remitValidation'
[address]='model.RemitAddress'
(onAddressChanged)='onFormChanged( $event )'>
</app-address>
我的app.module如下:
import { Component, OnInit, Input, Output, NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { CommonModule } from '@angular/common';
//
@Component({
selector: 'app-address',
template: `
<label for='Address1'>{{addressLabel}}</label>
<input type='text' id='Address1' name='Address1' required maxlength='50' class='nsg-input-wide'
#Address1='ngModel' [(ngModel)]='address1' (ngModelChange)='onDataChange( $event )'
placeholder='Address 1...' [disabled]='disabled' />
<div *ngIf='Address1.invalid && Address1.touched' style='color: red;'>
'Address 1' is required.
</div>
<label for='Address2'>Address 2:</label>
<input type='text' id='Address2' name='Address2' required maxlength='50' class='nsg-input-wide'
#Address2='ngModel' [(ngModel)]='address2' (ngModelChange)='onDataChange( $event )'
placeholder='Address 2...' [disabled]='disabled' />
`
})
export class AddressComponent implements OnInit {
@Input() disabled: boolean = true;
@Input() addressLabel: string = 'Address:';
@Input() address1: string = '';
@Input() address2: string = '';
//
constructor() { }
ngOnInit(): void { }
onDataChange( event: any ): boolean {
// this.onFormChanged.emit( event );
return false;
}
}
@NgModule({
declarations: [ AddressComponent ],
imports: [
CommonModule,
FormsModule
],
exports: [ AddressComponent ]
})
export class AddressModule { }
...
<app-address
[disabled]='addressDisabled'
[addressLabel]='addressLabel_1'
[address1]='address1_1'
[address2]='address2_1'>
</app-address>
<br />
<app-address
[disabled]='addressDisabled'
[addressLabel]='addressLabel_2'
[address1]='address1_2'
[address2]='address2_2'>
</app-address>
...
...
addressDisabled: boolean = false;
addressLabel_1: string = 'Office Address:';
address1_1: string = 'Address 1';
address2_1: string = 'Address 2';
addressLabel_2: string = 'Remit Address:';
address1_2: string = 'Address 1 2';
address2_2: string = 'Address 2 2';
...
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { CommonModule } from '@angular/common';
//
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { AddressComponent, AddressModule } from './scam/address/address.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
FormsModule,
CommonModule,
AppRoutingModule,
AddressModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
// ===========================================================================
// File: address.component.ts
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
//
import { IAddress, Address } from '../../admin/classes/address';
//
@Component({
selector: 'app-address',
template: `
<div class='row form-group' [class.has-error]='Address1.invalid && Address1.touched && validation'>
<div class='col-lg-3 col-md-4 col-sm-12 nsg-primary-color nsg-text-right'><label for='Address1{{uniquePostfix}}'>{{addressLabel}}</label></div>
<div class='col-lg-8 col-md-7 col-sm-12'>
<input type='text' id='Address1{{uniquePostfix}}' name='Address1{{uniquePostfix}}' required maxlength='50' class='nsg-input-wide'
#Address1='ngModel' [(ngModel)]='model.Address1' (ngModelChange)='onDataChange( $event )'
placeholder='Address 1...' [disabled]='disabled' />
</div>
<div class='col-lg-1 col-md-1 col-sm-12 nsg-alert-color' *ngIf='Address1.invalid && Address1.touched && validation'>Required</div>
</div>
<div class='row form-group'>
<div class='col-lg-3 col-md-4 col-sm-12 nsg-primary-color nsg-text-right'><label for='Address2{{uniquePostfix}}'> </label></div>
<div class='col-lg-8 col-md-7 col-sm-12'>
<input type='text' id='Address2{{uniquePostfix}}' name='Address2{{uniquePostfix}}' required maxlength='50' class='nsg-input-wide'
#Address2='ngModel' [(ngModel)]='model.Address2' (ngModelChange)='onDataChange( $event )'
placeholder='Address 2...' [disabled]='disabled' />
</div>
</div>
<div class='row form-group' [class.has-error]='(City.invalid && City.touched && validation) || (State.invalid && State.touched && validation) || (Zip.invalid && Zip.touched && validation) || (Country.invalid && Country.touched && validation)'>
<div class='col-lg-3 col-md-4 col-sm-12 nsg-primary-color nsg-text-right'><label for='City{{uniquePostfix}}'>{{cityStateLabel}}</label></div>
<div class='col-lg-auto col-md-auto col-sm-12'>
<input type='text' id='City{{uniquePostfix}}' name='City{{uniquePostfix}}' required maxlength='50' size='20'
#City='ngModel' [(ngModel)]='model.City' (ngModelChange)='onDataChange( $event )'
placeholder='City...' [disabled]='disabled' />
<input type='text' id='State{{uniquePostfix}}' name='State{{uniquePostfix}}' required maxlength='3' size='2'
#State='ngModel' [(ngModel)]='model.State' (ngModelChange)='onDataChange( $event )'
placeholder='State...' [disabled]='disabled' />
<input type='text' id='Zip{{uniquePostfix}}' name='Zip{{uniquePostfix}}' required maxlength='12' size='11'
#Zip='ngModel' [(ngModel)]='model.Zip' (ngModelChange)='onDataChange( $event )'
placeholder='Zip...' [disabled]='disabled' />
<input type='text' id='Country{{uniquePostfix}}' name='Country{{uniquePostfix}}' required maxlength='3' size='2'
#Country='ngModel' [(ngModel)]='model.Country' (ngModelChange)='onDataChange( $event )'
placeholder='Country...' [disabled]='disabled' />
</div>
<div class='col-lg-2 col-md-3 col-sm-12 nsg-alert-color' *ngIf='City.invalid || State.invalid || Zip.invalid || Country.invalid'>
<div *ngIf='City.invalid && City.touched && validation'>City Req.</div>
<div *ngIf='State.invalid && State.touched && validation'>State Req.</div>
<div *ngIf='Zip.invalid && Zip.touched && validation'>Zip Req.</div>
<div *ngIf='Country.invalid && Country.touched && validation'>Ctry Req.</div>
</div>
</div>
`
})
export class AddressComponent implements OnInit {
@Input() disabled: boolean = true;
@Input() addressLabel: string = 'Address:';
@Input() cityStateLabel: string = 'City/State/Zip:';
@Input() uniquePostfix: string = '';
@Input() validation: boolean = true;
model: IAddress;
@Input() set address( address: IAddress ) {
this.model = address;
}
get address(): IAddress { return this.model; }
@Output() onAddressChanged = new EventEmitter<boolean>();
//
constructor() {
// static constructor method
this.model = Address.empty( );
}
/*
** Component initialization, place all long running
** initializations here.
*/
ngOnInit(): void {
}
/*
** Events
** * flag that the form is dirty.
*/
onDataChange( event: any ): boolean {
this.onAddressChanged.emit( true );
return false;
}
//
}
// ===========================================================================
<app-address
[disabled]='!editable'
[uniquePostfix]='companyUniquePostfix'
[address]='model.CompanyAddress'
(onAddressChanged)='onFormChanged( $event )'>
</app-address>
<app-address
[disabled]='!editable'
[addressLabel]='remitAddressLabel'
[uniquePostfix]='remitUniquePostfix'
[validation]='remitValidation'
[address]='model.RemitAddress'
(onAddressChanged)='onFormChanged( $event )'>
</app-address>
现在,我希望有一个最佳实践解决方案,不重复地址的数据输入。我建议您研究反应式表单,这是创建自定义表单控件和通用表单控件的理想选择,因为您需要传递给子级的只是表单控件本身,它将保存任何初始值,验证等。在这里,您不仅可以对地址应用相同的自定义表单控件,还可以对您拥有的任何其他表单控件应用相同的自定义表单控件 这是一个适合你需要的样品。我会把地址作为一个表格组贴在一个表格里。在这个示例中,我还包括了一个“name”表单控件,只是为了演示可以为您拥有的任何其他表单控件添加这个自定义表单控件 好的,首先在应用程序模块中添加
ReactiveFormsModule
。然后,让我们在父级中构建表单:
从'@angular/forms'导入{FormArray、FormBuilder、FormGroup、Validators}
// ....
导出类AppComponent{
myForm:FormGroup;
//getter缩短了模板中所需的代码
获取地址arr(){
返回(this.myForm.get('addresses')作为FormArray.controls;
}
构造函数(私有fb:FormBuilder){
//使用验证器构建表单
this.myForm=this.fb.group({
名称:[''[Validators.minLength(10)],
地址:this.createAddresses()
});
}
//创建表单组并将其推送到formarray
createAddresses(){
让address=this.fb.array([]);
for(设i=0;i<3;i++){
地址推送(
本集团({
address1:[{value:'',已禁用:false},[Validators.maxLength(10)],
地址2:[{值:“”,已禁用:false}]
})
)
}
回信地址;
}
}
您正在使用disabled。上面我添加了disabled为false,如果您想在开始时禁用它,可以将其定义为true
子组件如下所示,它从父组件接受表单控件,显示字段以及存在的任何可能的验证错误:
从'@angular/core'导入{Component,Input};
从'@angular/forms'导入{FormControl,FormGroup};
@组成部分({
选择器:“你好”,
模板:`
最多20个字符!
最少10个字符!
`
})
导出类CustomFormControl{
@输入()ctrl:FormControl;
@Input()占位符:字符串;
}
然后在父组件中,我们只需将子组件添加到它们所属的位置(对于formarray,我们需要迭代,命名formgroup,我们使用它的索引)并将formcontrol传递给子组件。就这些
这里有一个供您参考。对于这个模板驱动的答案,我不得不改变一些方法。利用模板驱动的可变性,将类传递给组件工作得更好
// ===========================================================================
// File: address.ts
export interface IAddress {
Address1: string;
Address2: string;
City: string;
State: string;
Zip: string;
Country: string;
toString( ): string;
getAddress( ): string;
}
//
export class Address implements IAddress {
/*
** Create an empty/new instance.
** (Should occur first in class per lint)
*/
public static empty( ): IAddress {
return new Address( '', '', '', '', '', '' );
}
//
constructor(
public Address1: string,
public Address2: string,
public City: string,
public State: string,
public Zip: string,
public Country: string,
) { }
/*
** Combine numerous address fields.
*/
getAddress(): string {
const _addr: string = (this.Address2 !== '' ?
`${this.Address1}, ${this.Address2}` :
this.Address1 );
return `${_addr}, ${this.City}, ${this.State} ${this.Zip} ${this.Country}`;
}
/*
** toString implementation for class address
*/
public toString = (): string => {
return JSON.stringify( this );
}
//
}
// ===========================================================================
组成部分如下:
import { Component, OnInit, Input, Output, NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { CommonModule } from '@angular/common';
//
@Component({
selector: 'app-address',
template: `
<label for='Address1'>{{addressLabel}}</label>
<input type='text' id='Address1' name='Address1' required maxlength='50' class='nsg-input-wide'
#Address1='ngModel' [(ngModel)]='address1' (ngModelChange)='onDataChange( $event )'
placeholder='Address 1...' [disabled]='disabled' />
<div *ngIf='Address1.invalid && Address1.touched' style='color: red;'>
'Address 1' is required.
</div>
<label for='Address2'>Address 2:</label>
<input type='text' id='Address2' name='Address2' required maxlength='50' class='nsg-input-wide'
#Address2='ngModel' [(ngModel)]='address2' (ngModelChange)='onDataChange( $event )'
placeholder='Address 2...' [disabled]='disabled' />
`
})
export class AddressComponent implements OnInit {
@Input() disabled: boolean = true;
@Input() addressLabel: string = 'Address:';
@Input() address1: string = '';
@Input() address2: string = '';
//
constructor() { }
ngOnInit(): void { }
onDataChange( event: any ): boolean {
// this.onFormChanged.emit( event );
return false;
}
}
@NgModule({
declarations: [ AddressComponent ],
imports: [
CommonModule,
FormsModule
],
exports: [ AddressComponent ]
})
export class AddressModule { }
...
<app-address
[disabled]='addressDisabled'
[addressLabel]='addressLabel_1'
[address1]='address1_1'
[address2]='address2_1'>
</app-address>
<br />
<app-address
[disabled]='addressDisabled'
[addressLabel]='addressLabel_2'
[address1]='address1_2'
[address2]='address2_2'>
</app-address>
...
...
addressDisabled: boolean = false;
addressLabel_1: string = 'Office Address:';
address1_1: string = 'Address 1';
address2_1: string = 'Address 2';
addressLabel_2: string = 'Remit Address:';
address1_2: string = 'Address 1 2';
address2_2: string = 'Address 2 2';
...
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { CommonModule } from '@angular/common';
//
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { AddressComponent, AddressModule } from './scam/address/address.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
FormsModule,
CommonModule,
AppRoutingModule,
AddressModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
// ===========================================================================
// File: address.component.ts
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
//
import { IAddress, Address } from '../../admin/classes/address';
//
@Component({
selector: 'app-address',
template: `
<div class='row form-group' [class.has-error]='Address1.invalid && Address1.touched && validation'>
<div class='col-lg-3 col-md-4 col-sm-12 nsg-primary-color nsg-text-right'><label for='Address1{{uniquePostfix}}'>{{addressLabel}}</label></div>
<div class='col-lg-8 col-md-7 col-sm-12'>
<input type='text' id='Address1{{uniquePostfix}}' name='Address1{{uniquePostfix}}' required maxlength='50' class='nsg-input-wide'
#Address1='ngModel' [(ngModel)]='model.Address1' (ngModelChange)='onDataChange( $event )'
placeholder='Address 1...' [disabled]='disabled' />
</div>
<div class='col-lg-1 col-md-1 col-sm-12 nsg-alert-color' *ngIf='Address1.invalid && Address1.touched && validation'>Required</div>
</div>
<div class='row form-group'>
<div class='col-lg-3 col-md-4 col-sm-12 nsg-primary-color nsg-text-right'><label for='Address2{{uniquePostfix}}'> </label></div>
<div class='col-lg-8 col-md-7 col-sm-12'>
<input type='text' id='Address2{{uniquePostfix}}' name='Address2{{uniquePostfix}}' required maxlength='50' class='nsg-input-wide'
#Address2='ngModel' [(ngModel)]='model.Address2' (ngModelChange)='onDataChange( $event )'
placeholder='Address 2...' [disabled]='disabled' />
</div>
</div>
<div class='row form-group' [class.has-error]='(City.invalid && City.touched && validation) || (State.invalid && State.touched && validation) || (Zip.invalid && Zip.touched && validation) || (Country.invalid && Country.touched && validation)'>
<div class='col-lg-3 col-md-4 col-sm-12 nsg-primary-color nsg-text-right'><label for='City{{uniquePostfix}}'>{{cityStateLabel}}</label></div>
<div class='col-lg-auto col-md-auto col-sm-12'>
<input type='text' id='City{{uniquePostfix}}' name='City{{uniquePostfix}}' required maxlength='50' size='20'
#City='ngModel' [(ngModel)]='model.City' (ngModelChange)='onDataChange( $event )'
placeholder='City...' [disabled]='disabled' />
<input type='text' id='State{{uniquePostfix}}' name='State{{uniquePostfix}}' required maxlength='3' size='2'
#State='ngModel' [(ngModel)]='model.State' (ngModelChange)='onDataChange( $event )'
placeholder='State...' [disabled]='disabled' />
<input type='text' id='Zip{{uniquePostfix}}' name='Zip{{uniquePostfix}}' required maxlength='12' size='11'
#Zip='ngModel' [(ngModel)]='model.Zip' (ngModelChange)='onDataChange( $event )'
placeholder='Zip...' [disabled]='disabled' />
<input type='text' id='Country{{uniquePostfix}}' name='Country{{uniquePostfix}}' required maxlength='3' size='2'
#Country='ngModel' [(ngModel)]='model.Country' (ngModelChange)='onDataChange( $event )'
placeholder='Country...' [disabled]='disabled' />
</div>
<div class='col-lg-2 col-md-3 col-sm-12 nsg-alert-color' *ngIf='City.invalid || State.invalid || Zip.invalid || Country.invalid'>
<div *ngIf='City.invalid && City.touched && validation'>City Req.</div>
<div *ngIf='State.invalid && State.touched && validation'>State Req.</div>
<div *ngIf='Zip.invalid && Zip.touched && validation'>Zip Req.</div>
<div *ngIf='Country.invalid && Country.touched && validation'>Ctry Req.</div>
</div>
</div>
`
})
export class AddressComponent implements OnInit {
@Input() disabled: boolean = true;
@Input() addressLabel: string = 'Address:';
@Input() cityStateLabel: string = 'City/State/Zip:';
@Input() uniquePostfix: string = '';
@Input() validation: boolean = true;
model: IAddress;
@Input() set address( address: IAddress ) {
this.model = address;
}
get address(): IAddress { return this.model; }
@Output() onAddressChanged = new EventEmitter<boolean>();
//
constructor() {
// static constructor method
this.model = Address.empty( );
}
/*
** Component initialization, place all long running
** initializations here.
*/
ngOnInit(): void {
}
/*
** Events
** * flag that the form is dirty.
*/
onDataChange( event: any ): boolean {
this.onAddressChanged.emit( true );
return false;
}
//
}
// ===========================================================================
<app-address
[disabled]='!editable'
[uniquePostfix]='companyUniquePostfix'
[address]='model.CompanyAddress'
(onAddressChanged)='onFormChanged( $event )'>
</app-address>
<app-address
[disabled]='!editable'
[addressLabel]='remitAddressLabel'
[uniquePostfix]='remitUniquePostfix'
[validation]='remitValidation'
[address]='model.RemitAddress'
(onAddressChanged)='onFormChanged( $event )'>
</app-address>
//===========================================================================
//文件:address.component.ts
从“@angular/core”导入{Component,OnInit,Input,Output,EventEmitter};
//
从“../../admin/classes/Address”导入{IAddress,Address};
//
@组成部分({
选择器:“应用程序地址”,
模板:`
{{addressLabel}}
要求的
{{cityStateLabel}}
城市请求。
状态请求。
Zip请求。
Ctry请求。
`
})
导出类AddressComponent实现OnInit{
@Input()已禁用:布尔值=true;
@Input()addressLabel:string='地址:';
@Input()城市标签:字符串='City/State/Zip:';
@Input()uniquePostfix:string='';
@输入()验证:布尔值=true;
模特:女装;
@Input()设置地址(地址:IADRESS){
this.model=地址;
}
获取地址():IAddress{返回this.model;}
@Output()onAddressChanged=新的EventEmitter();
//
构造函数(){
//静态构造函数方法
this.model=Address.empty();
}
/*
**组件初始化,放置所有长时间运行
**这里的初始化。
*/
ngOnInit():void{
}
/*
**事件
***标记窗体已脏。
*/
onDataChange(事件:任意):布尔值{
this.onAddressChanged.emit(true);
返回false;
}
//
}
// ===========================================================================
uniquePostfix的输入用于使DOM满意。
用法如下:
import { Component, OnInit, Input, Output, NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { CommonModule } from '@angular/common';
//
@Component({
selector: 'app-address',
template: `
<label for='Address1'>{{addressLabel}}</label>
<input type='text' id='Address1' name='Address1' required maxlength='50' class='nsg-input-wide'
#Address1='ngModel' [(ngModel)]='address1' (ngModelChange)='onDataChange( $event )'
placeholder='Address 1...' [disabled]='disabled' />
<div *ngIf='Address1.invalid && Address1.touched' style='color: red;'>
'Address 1' is required.
</div>
<label for='Address2'>Address 2:</label>
<input type='text' id='Address2' name='Address2' required maxlength='50' class='nsg-input-wide'
#Address2='ngModel' [(ngModel)]='address2' (ngModelChange)='onDataChange( $event )'
placeholder='Address 2...' [disabled]='disabled' />
`
})
export class AddressComponent implements OnInit {
@Input() disabled: boolean = true;
@Input() addressLabel: string = 'Address:';
@Input() address1: string = '';
@Input() address2: string = '';
//
constructor() { }
ngOnInit(): void { }
onDataChange( event: any ): boolean {
// this.onFormChanged.emit( event );
return false;
}
}
@NgModule({
declarations: [ AddressComponent ],
imports: [
CommonModule,
FormsModule
],
exports: [ AddressComponent ]
})
export class AddressModule { }
...
<app-address
[disabled]='addressDisabled'
[addressLabel]='addressLabel_1'
[address1]='address1_1'
[address2]='address2_1'>
</app-address>
<br />
<app-address
[disabled]='addressDisabled'
[addressLabel]='addressLabel_2'
[address1]='address1_2'
[address2]='address2_2'>
</app-address>
...
...
addressDisabled: boolean = false;
addressLabel_1: string = 'Office Address:';
address1_1: string = 'Address 1';
address2_1: string = 'Address 2';
addressLabel_2: string = 'Remit Address:';
address1_2: string = 'Address 1 2';
address2_2: string = 'Address 2 2';
...
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { CommonModule } from '@angular/common';
//
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { AddressComponent, AddressModule } from './scam/address/address.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
FormsModule,
CommonModule,
AppRoutingModule,
AddressModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
// ===========================================================================
// File: address.component.ts
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
//
import { IAddress, Address } from '../../admin/classes/address';
//
@Component({
selector: 'app-address',
template: `
<div class='row form-group' [class.has-error]='Address1.invalid && Address1.touched && validation'>
<div class='col-lg-3 col-md-4 col-sm-12 nsg-primary-color nsg-text-right'><label for='Address1{{uniquePostfix}}'>{{addressLabel}}</label></div>
<div class='col-lg-8 col-md-7 col-sm-12'>
<input type='text' id='Address1{{uniquePostfix}}' name='Address1{{uniquePostfix}}' required maxlength='50' class='nsg-input-wide'
#Address1='ngModel' [(ngModel)]='model.Address1' (ngModelChange)='onDataChange( $event )'
placeholder='Address 1...' [disabled]='disabled' />
</div>
<div class='col-lg-1 col-md-1 col-sm-12 nsg-alert-color' *ngIf='Address1.invalid && Address1.touched && validation'>Required</div>
</div>
<div class='row form-group'>
<div class='col-lg-3 col-md-4 col-sm-12 nsg-primary-color nsg-text-right'><label for='Address2{{uniquePostfix}}'> </label></div>
<div class='col-lg-8 col-md-7 col-sm-12'>
<input type='text' id='Address2{{uniquePostfix}}' name='Address2{{uniquePostfix}}' required maxlength='50' class='nsg-input-wide'
#Address2='ngModel' [(ngModel)]='model.Address2' (ngModelChange)='onDataChange( $event )'
placeholder='Address 2...' [disabled]='disabled' />
</div>
</div>
<div class='row form-group' [class.has-error]='(City.invalid && City.touched && validation) || (State.invalid && State.touched && validation) || (Zip.invalid && Zip.touched && validation) || (Country.invalid && Country.touched && validation)'>
<div class='col-lg-3 col-md-4 col-sm-12 nsg-primary-color nsg-text-right'><label for='City{{uniquePostfix}}'>{{cityStateLabel}}</label></div>
<div class='col-lg-auto col-md-auto col-sm-12'>
<input type='text' id='City{{uniquePostfix}}' name='City{{uniquePostfix}}' required maxlength='50' size='20'
#City='ngModel' [(ngModel)]='model.City' (ngModelChange)='onDataChange( $event )'
placeholder='City...' [disabled]='disabled' />
<input type='text' id='State{{uniquePostfix}}' name='State{{uniquePostfix}}' required maxlength='3' size='2'
#State='ngModel' [(ngModel)]='model.State' (ngModelChange)='onDataChange( $event )'
placeholder='State...' [disabled]='disabled' />
<input type='text' id='Zip{{uniquePostfix}}' name='Zip{{uniquePostfix}}' required maxlength='12' size='11'
#Zip='ngModel' [(ngModel)]='model.Zip' (ngModelChange)='onDataChange( $event )'
placeholder='Zip...' [disabled]='disabled' />
<input type='text' id='Country{{uniquePostfix}}' name='Country{{uniquePostfix}}' required maxlength='3' size='2'
#Country='ngModel' [(ngModel)]='model.Country' (ngModelChange)='onDataChange( $event )'
placeholder='Country...' [disabled]='disabled' />
</div>
<div class='col-lg-2 col-md-3 col-sm-12 nsg-alert-color' *ngIf='City.invalid || State.invalid || Zip.invalid || Country.invalid'>
<div *ngIf='City.invalid && City.touched && validation'>City Req.</div>
<div *ngIf='State.invalid && State.touched && validation'>State Req.</div>
<div *ngIf='Zip.invalid && Zip.touched && validation'>Zip Req.</div>
<div *ngIf='Country.invalid && Country.touched && validation'>Ctry Req.</div>
</div>
</div>
`
})
export class AddressComponent implements OnInit {
@Input() disabled: boolean = true;
@Input() addressLabel: string = 'Address:';
@Input() cityStateLabel: string = 'City/State/Zip:';
@Input() uniquePostfix: string = '';
@Input() validation: boolean = true;
model: IAddress;
@Input() set address( address: IAddress ) {
this.model = address;
}
get address(): IAddress { return this.model; }
@Output() onAddressChanged = new EventEmitter<boolean>();
//
constructor() {
// static constructor method
this.model = Address.empty( );
}
/*
** Component initialization, place all long running
** initializations here.
*/
ngOnInit(): void {
}
/*
** Events
** * flag that the form is dirty.
*/
onDataChange( event: any ): boolean {
this.onAddressChanged.emit( true );
return false;
}
//
}
// ===========================================================================
<app-address
[disabled]='!editable'
[uniquePostfix]='companyUniquePostfix'
[address]='model.CompanyAddress'
(onAddressChanged)='onFormChanged( $event )'>
</app-address>
<app-address
[disabled]='!editable'
[addressLabel]='remitAddressLabel'
[uniquePostfix]='remitUniquePostfix'
[validation]='remitValidation'
[address]='model.RemitAddress'
(onAddressChanged)='onFormChanged( $event )'>
</app-address>
我建议您查看ControlValueAccesor界面,了解您的回答。我通过几门多视距课程学习Angular 2。我以前没有真正使用过反应式。我已经成功地移植了一个表单,以便在我的参考应用程序中进行响应。我有一个生命周期问题,但它现在正在工作。在这一点上,我有很多模板驱动的代码,我没有看到太多的功能差异。