问题
This is so commonly used, there must be a simple way to approach this! So here is the situation. I have a form group:
<ion-item-group formGroupName="alternativeRevenue">
<ion-item-divider color="primary" text-wrap sticky>Alternative revenue </ion-item-divider>
<ion-item>
<ion-label>Branded content</ion-label>
<ion-toggle formControlName="brandedContent"></ion-toggle>
</ion-item>
<ion-item text-wrap *ngIf="businessFoundationsForm.get('alternativeRevenue.brandedContent').value">
<ion-label floating>you want to work with?</ion-label>
<ion-input formControlName="typesOfBrands"></ion-input>
</ion-item>
<ion-item>
<ion-label>Merchandise</ion-label>
<ion-toggle formControlName="merchandise"></ion-toggle>
</ion-item>
<ion-item text-wrap *ngIf="businessFoundationsForm.get('alternativeRevenue.merchandise').value">
<ion-label floating>What types of brands</ion-label>
<ion-input formControlName="typeOfMerchandise"></ion-input>
</ion-item>
<ion-item>
<ion-label>Podcasts</ion-label>
<ion-toggle formControlName="podcasts"></ion-toggle>
</ion-item>
<ion-item text-wrap *ngIf="businessFoundationsForm.get('alternativeRevenue.podcasts').value">
<ion-label floating>Brainstorm topic ideas </ion-label>
<ion-textarea fz-elastic formControlName="podcastIdeas"></ion-textarea>
</ion-item>
<ion-item>
<ion-label>Tours</ion-label>
<ion-toggle formControlName="tours"></ion-toggle>
</ion-item>
<ion-item text-wrap *ngIf="businessFoundationsForm.get('alternativeRevenue.tours').value">
<ion-label floating>Brainstorm tour </ion-label>
<ion-textarea fz-elastic formControlName="tourIdeas"></ion-textarea>
</ion-item>
<ion-item>
<ion-label>Deals</ion-label>
<ion-toggle formControlName="licensingDeals"></ion-toggle>
</ion-item>
<ion-item text-wrap *ngIf="businessFoundationsForm.get('alternativeRevenue.licensingDeals').value">
<ion-label floating>Two ideas for licensing</ion-label>
<ion-textarea fz-elastic formControlName="licensingIdeas"></ion-textarea>
</ion-item>
</ion-item-group>
And here is the Form group in component:
alternativeRevenue: this.fb.group({
brandedContent: [false],
typesOfBrands: [null],
merchandise: [false],
typeOfMerchandise: [null],
podcasts: [false],
podcastIdeas: [null],
tours: [false],
tourIdeas: [null],
licensingDeals: [false],
licensingIdeas: [null]
}, {validator: alternativeRevenueGroupValidator})
My goal is, if one of the select / ion-toggle is true, and the associated input filed is NOT empty and has min length of more than 10, the from group is validated. If I add the [Validators.required, Validators.minLength(10)] to all the field, it will require all the field to be filled before the form group to be validated. I just want ONE of them to be validate and then the whole group is validate. How can I do that?
UPDATE: here is the alternativeRevenueGroupValidator.
function alternativeRevenueGroupValidator(c: AbstractControl) {
let brandedContent = c.get('brandedContent');
let typesOfBrands = c.get('typesOfBrands');
let merchandise = c.get('merchandise');
let typeOfMerchandise = c.get('typeOfMerchandise');
let podcasts = c.get('podcasts');
let podcastIdeas = c.get('podcastIdeas');
let tours = c.get('tours');
let tourIdeas = c.get('tourIdeas');
let licensingDeals = c.get('licensingDeals');
let licensingIdeas = c.get('licensingIdeas');
if (brandedContent || merchandise || podcasts|| tours || licensingDeals) {
if (typesOfBrands.value || typeOfMerchandise.value || podcastIdeas.value || tourIdeas.value || licensingIdeas.value) {
return null;
}
}
return {'GroupNoValue': true};
}
As you see it is VERY UGLY. And it can ONLY validate if the input field has value or not. I can not value the min or max length or use library like this enter link description here
回答1:
The second parameter to the FormGroup
constructor lets you define a custom group validator.
Within the group validator, determine if the conditions are satisfied for a valid form (i.e. at least one input field is non-empty, and has a field length greater than 10). If the form is valid, clear the individual errors by calling control.setErrors(null)
. Otherwise, return a custom error object: { 'atLeastOneInputFieldMustBeValid': true }
so you can bind to it later.
function alternativeRevenueGroupValidator(c: FormGroup) {
let brandedContent = c.get('brandedContent');
let typesOfBrands = c.get('typesOfBrands');
let merchandise = c.get('merchandise');
let typeOfMerchandise = c.get('typeOfMerchandise');
let podcasts = c.get('podcasts');
let podcastIdeas = c.get('podcastIdeas');
let tours = c.get('tours');
let tourIdeas = c.get('tourIdeas');
let licensingDeals = c.get('licensingDeals');
let licensingIdeas = c.get('licensingIdeas');
if (brandedContent.valid ||
merchandise.valid ||
podcasts.valid ||
tours.valid ||
licensingDeals.valid ||
typesOfBrands.valid ||
typesOfMerchandise.valid ||
postcastIdeas.valid ||
tourIdeas.valid ||
licensingIdeas.valid) {
brandedContent.setErrors(null);
merchandise.setErrors(null);
podcasts.setErrors(null);
tours.setErrors(null);
licensingDeals.setErrors(null);
typesOfBrands.setErrors(null);
typesOfMerchandise.setErrors(null);
postcastIdeas.setErrors(null);
tourIdeas.setErrors(null);
licensingIdeas.setErrors(null);
return null;
}
}
return {'GroupNoValue': true};
}
Within the group validator function, you have the flexibility to inspect the validation flags of any control within the group, set the error object of any one of the controls, and finally you can return any validation object with any number of validation flags set.
If you require at least two of the fields to be required, and greater than 10 charaters, you might do something like this:
function alternativeRevenueGroupValidator(c: FormGroup) {
var validCtls = c.controls.filter(c=> c.valid);
if (validCtls.length >= 2) {
c.controls.forEach((t)=> t.setErrors(null));
return null;
}
return {'GroupNoTwoValues': true};
}
来源:https://stackoverflow.com/questions/42591609/how-to-do-simple-cross-field-validation-in-angular-2-form-to-pass-validation-if