typescript - Angular-formulär returnerar alltid ogiltigt?
Jag har ett Angular reaktivt formulär med tre kryssrutor:
- Den första kryssrutan är för att se om användaren vill förbli anonym. Om användaren lämnar denna okryssad, förblir namnfältet kvar. Om den är ikryssad, döljs namnfältet.
- Den andra kryssrutan är för att visa ett e-postfält. Om den är markerad visas e-postfältet. Om den förblir omarkerad visas inte e-postfältet.
- Den tredje kryssrutan är en 'Godkänn'-kryssruta. Användaren måste markera denna för att kunna skicka in formuläret.
Mitt problem är att, även om alla dessa krav uppfylls, är inlämningsformuläret fortfarande ogiltigt. Jag skulle vilja se att mitt submissionForm.valid returnerar true. Här är min komponent för inlämningsformuläret:
REDIGERA: tack vare svaret i kommentarerna ser jag att alla mina fält returnerar null-värden. Kan någon vänligen hjälpa mig att fixa detta också? Jag känner att jag initialiserar allt korrekt men jag är fortfarande förvirrad över varför värdena returnerar som null.
import { Component, OnInit } from '@angular/core';
import { FormGroup, Validators, FormBuilder } from '@angular/forms';
@Component({
selector: 'app-submission',
templateUrl: './submission-form.component.html',
styleUrls: [
'./submission-form.component.scss'
]
})
export class SubmissionFormComponent implements OnInit {
submissionForm: FormGroup;
formSubmitted = false; //Holds status of the form
private nameValidators = [
Validators.minLength(1),
Validators.maxLength(50)
];
private emailValidators = [
Validators.maxLength(250),
Validators.email
];
constructor(private fb: FormBuilder) { }
ngOnInit(): void {
this.createForm();
}
createForm(): void {
this.submissionForm = this.fb.group({
anonymous: [''],
name: ['', this.nameValidators],
contact: [''],
email: ['', this.emailValidators],
contentWarning: ['', [Validators.required]],
title: ['', Validators.required],
message: ['', [Validators.required, Validators.minLength(10), Validators.maxLength(10000)]],
agree: [false, [Validators.requiredTrue]]
});
}
onSubmit() {
if (this.submissionForm.get('anonymous').value == false) {
this.submissionForm.get('name').setValidators(this.nameValidators.concat(Validators.required));
} else {
this.submissionForm.get('name').setValidators(this.nameValidators);
}
if (this.submissionForm.get('contact').value == true) {
this.submissionForm.get('email').setValidators(this.emailValidators.concat(Validators.required));
} else {
this.submissionForm.get('email').setValidators(this.emailValidators);
}
this.formSubmitted = true; //Form has been submitted
console.log(this.submissionForm.valid);
if (this.submissionForm.valid) {
console.log('submissionForm', this.submissionForm.value); //Process the form
}
}
get anonymous() { return this.submissionForm.get('anonymous') };
get name() { return this.submissionForm.get('name') };
get contact() { return this.submissionForm.get('contact') };
get email() { return this.submissionForm.get('email') };
get contentWarning() { return this.submissionForm.get('contentWarning') };
get title() { return this.submissionForm.get('title') };
get message() { return this.submissionForm.get('message') };
get agree() { return this.submissionForm.get('agree') };
}Här är den medföljande mallkoden:
<section class="section">
<div class="columns is-centered">
<div class="column is-four-fifths">
<h1 class="title">Submission Form</h1>
<p class="success" *ngIf="formSubmitted">Submitted successfully</p>
<form [formGroup]="submissionForm" (ngSubmit)="onSubmit()">
<div class="field">
<!--Checkbox for remaining anonymous-->
<label class="checkbox">
<input type="checkbox"
formControlName="anonymous">
Remain anonymous
</label>
</div>
<div class="field" [hidden]="anonymous.value">
<!--Checkbox for remaining anonymous-->
<input class="input"
type="text"
placeholder="Name"
formControlName="name"
[ngClass]="{'form-submitted': formSubmitted}">
<div class="help-is-danger" *ngIf="name.invalid && !name.pristine">Name should be 50 characters or less.</div>
</div>
<div class="field">
<!--Checkbox for being contacted-->
<label class="checkbox">
<input type="checkbox" formControlName="contact">
Contact me
</label>
</div>
<div class="field" [hidden]="!contact.value">
<!--Field for email-->
<input class="input"
type="text"
placeholder="Email"
formControlName="email"
[ngClass]="{'form-submitted': formSubmitted}">
<div class="help-is-danger" *ngIf="email.invalid && !email.pristine">
<p *ngIf="email.errors.email">Valid email is required.</p>
</div>
</div>
<div class="field">
<!--Field for content warnings-->
<input class="input"
type="text"
placeholder="Content warnings"
formControlName="name"
[ngClass]="{'form-submitted': formSubmitted}">
<div class="help-is-danger" *ngIf="contentWarning.invalid && !contentWarning.pristine">Content warnings are required.</div>
</div>
<div class="field">
<!--Field for title-->
<input class="input"
type="text"
placeholder="Title"
formControlName="title"
[ngClass]="{'form-submitted': formSubmitted}">
<div class="help-is-danger" *ngIf="title.invalid && !title.pristine">Title is required.</div>
</div>
<div class="field">
<!--Text area for message-->
<textarea class="textarea"
type="text"
placeholder="Your Submission"
formControlName="message">
</textarea>
<div class="help-is-danger" *ngIf="message.invalid && !message.pristine">
<p *ngIf="message.errors.minlength">Message is required and should be at least 10 characters.</p>
</div>
</div>
<div class="field">
<!--Checkbox for agree-->
<label class="checkbox">
<input type="checkbox"
formControlName="agree">
Agree
</label>
<div class="help-is-danger" *ngIf="submissionForm.hasError('required', 'agree') && !agree.pristine">Must check 'Agree' in order to submit.</div>
</div>
<!--Submit Button-->
<button type="submit" class="button is-danger is-outlined" [disabled]="!agree.valid && !submissionForm.valid">Submit</button>
</form>
</div>
</div>
</section>Jag använder för närvarande Angular 9 och Bulma-ramverket.
Svar #1
Eftersom du har fält som måste följa vissa regler endast när de är synliga, och deras synlighetsstatus beror på värdet av andra kontroller, måste du skriva några egna validatorer. Du har två sätt att göra det på: antingen genom att applicera de egna validatorerna direkt på kontrollerna, eller genom att applicera dem på formuläret. Båda är ganska omständliga och jag kommer här att ta med den jag tycker är lättast att förstå, vilket är att applicera dem på formuläret.
Stackblitz-demonstration
Det är viktigt att notera att jag bara svarar på ditt krav för validatorer. Det betyder inte att detta är det bästa eller enklaste sättet att uppnå den UX du vill ha.
Byt ut validerarna för dessa två fält mot anpassade validerare som tillämpas på formuläret:
createForm(): void {
this.submissionForm = this.fb.group(
{
...
name: [''], // <= no validators here
...
email: [''], // <= no validators here
...
},
// apply two custom validators to the form
{ validators: [validateName, validateEmail] }
);
}
Skriv dina egna validatorer:
function validateEmail(formGroup: FormGroup): ValidationErrors {
const anonymousCtrl = formGroup && formGroup.get('contact');
if (!anonymousCtrl || !anonymousCtrl.value) {return null;}
const control = formGroup.get('email');
const regex = /^([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$/;
const emailMalformed = !regex.test(control.value);
const emailRequired = !control.value;
let error = {};
if (emailMalformed) error = { ...error, emailMalformed: true };
if (emailRequired) error = { ...error, emailRequired: true };
return Object.keys(error).length ? error : null;
}
function validateName(formGroup: FormGroup): ValidationErrors {
const anonymousCtrl = formGroup && formGroup.get('anonymous');
if (!anonymousCtrl || anonymousCtrl.value) {return null;}
const control = formGroup.get('name');
const nameMaxLength = control.value && control.value.length > 250;
const nameRequired = !control.value;
let error = {};
if (nameMaxLength) error = { ...error, nameMaxLength: true };
if (nameRequired) error = { ...error, nameRequired: true };
return Object.keys(error).length ? error : null;
}
Fixa din mall så att den visar felen på kontrollerna när de inträffar
<input formControlName="name">
<div class="help-is-danger"
*ngIf="nameInvalid && !name.pristine">
Name should be 50 characters or less.
</div>
...
<input formControlName="email">
<div class="help-is-danger"
*ngIf="emailInvalid && !email.pristine">
A valid email is required.
</div>
Skriv getters nameInvalid och emailInvalid:
get nameInvalid() {
return (
this.submissionForm.getError('nameRequired') ||
this.submissionForm.getError('nameMaxLength')
);
}
get emailInvalid() {
return (
this.submissionForm.getError('emailRequired') ||
this.submissionForm.getError('emailMalformed')
);
}
Svar #2
Även om du döljer dessa fält, kräver formuläret fortfarande värde för att uppfylla dess valideringsregler.
för att inaktivera validatorn i namn- och e-postfältet behöver du inaktivera det reaktiva formulärfältet
if (this.submissionForm.get('anonymous').value == false) {
this.submissionForm.get('name').enable()
}
else{
this.submissionForm.get('name').disable();
}
det kommer att vara bättre att använda detta if else på rxjs-sätt
this.submissionForm.get('anonymous').valueChanges.subscribe(
value => {
if (value == false) {
this.submissionForm.get('name').enable()
}
else{
this.submissionForm.get('name').disable();
}
}
)
