-
Notifications
You must be signed in to change notification settings - Fork 38
Angular Reactive Forms
"As of Angular 14-16, reactive forms are strictly typed by default.", however, constructing typed FormGroup in TypeScript codes is still a manual process. Before the Angular team would develop respective features, WebApiClientGen can generate client API codes that generate FormGroups which include validation codes according to annotation attributes decorating class properties or fields.
Attribute | NG Validators |
---|---|
Required | required |
MaxLength | maxLength |
MinLength | minLength |
StringLength | minLength maxLength if each is greater than zero |
Range | min max if Maximum or Minimum is defined |
EmailAddress |
Property or field of nested complex objects is not supported.
Property of field of array is not supported.
Default value of property is not supported, and System.ComponentModel.DefaultValueAttribute is not supported. #136
The data models particularly with nested structure may not have one to one mapping to the UI/UX design.
Array is not supported.
For examples:
Declarative info of data constraints in C#
/// <summary>
/// Base class of company and person
/// </summary>
[DataContract(Namespace = Constants.DataNamespace)]
public class Entity
{
public Entity()
{
Addresses = new List<Address>();
}
[DataMember]
public Guid? Id { get; set; }
/// <summary>
/// Name of the entity.
/// </summary>
[DataMember(IsRequired =true)]//MVC and Web API does not care
[System.ComponentModel.DataAnnotations.Required]//MVC and Web API care about only this
[MinLength(2), MaxLength(255)]
public string Name { get; set; }
/// <summary>
/// Multiple addresses
/// </summary>
[DataMember]
public IList<Address> Addresses { get; set; }
[DataMember]
public virtual ObservableCollection<PhoneNumber> PhoneNumbers { get; set; }
public override string ToString()
{
return Name;
}
[DataMember]
public Uri Web { get; set; }
[DataMember, EmailAddress, MaxLength(255)]
public string EmailAddress { get; set; }
}
[DataContract(Namespace = Constants.DataNamespace)]
public class Person : Entity
{
[DataMember]
public string Surname { get; set; }
[DataMember]
public string GivenName { get; set; }
/// <summary>
/// Date of Birth.
/// This is optional.
/// </summary>
[DataMember]
public DateOnly? DOB { get; set; }
[DataMember]
[DataType(DataType.Date)]
public DateTimeOffset? Baptised { get; set; }
public override string ToString()
{
return Surname + ", " + GivenName;
}
}
Typed FormGroups generated
export interface Person extends DemoWebApi_DemoData_Base_Client.Entity {
/** Data type: Date */
baptised?: Date | null;
/**
* Date of Birth.
* This is optional.
*/
dob?: Date | null;
givenName?: string | null;
surname?: string | null;
}
export interface PersonFormProperties extends DemoWebApi_DemoData_Base_Client.EntityFormProperties {
/** Data type: Date */
baptised: FormControl<Date | null | undefined>,
/**
* Date of Birth.
* This is optional.
*/
dob: FormControl<Date | null | undefined>,
givenName: FormControl<string | null | undefined>,
surname: FormControl<string | null | undefined>,
}
export function CreatePersonFormGroup() {
return new FormGroup<PersonFormProperties>({
emailAddress: new FormControl<string | null | undefined>(undefined, [Validators.email, Validators.maxLength(255)]),
id: new FormControl<string | null | undefined>(undefined),
name: new FormControl<string | null | undefined>(undefined, [Validators.required, Validators.minLength(2), Validators.maxLength(255)]),
web: new FormControl<string | null | undefined>(undefined),
baptised: new FormControl<Date | null | undefined>(undefined),
dob: new FormControl<Date | null | undefined>(undefined),
givenName: new FormControl<string | null | undefined>(undefined),
surname: new FormControl<string | null | undefined>(undefined),
});
}