Getting a 'Path Error' with nested forms Array - javascript

I have the following html:
<form [formGroup]="customFieldForm">
..........
<div formArrayName="FieldNames">
<div *ngFor="let fieldName of customFieldForm.get('FieldNames').controls; let i = index"
[formGroupName]="i">
<mat-form-field>
<input matInput [value]="fieldName.value.CustomFieldName"
[formControlName]="CustomFieldName"
[placeholder]="placeHolderInLocalLanguage">
</mat-form-field>
</div>
</form
I'm getting the following error:
Cannot find control with path: 'FieldNames -> 0 (and all the length of the array...) ->
the TS file :
this.customFieldForm = new FormGroup({
Menu: new FormControl(null, Validators.required),
FieldType: new FormControl(null, Validators.required),
FieldNames : new FormArray([]),
OptionalOrMendatory: new FormControl(false),
LineTypes: new FormControl(null),
})
the Initiation Of data from server:
this.data.forEach(nameAndLanguage => {
const FieldName: FormGroup = this.fb.group({
CustomFieldName: nameAndLanguage.CustomFieldName,
ID: nameAndLanguage.LanguageID
});
(<FormArray>this.customFieldForm.get('FieldNames')).push(FieldName);
})
Any one can spot what I'm doing wrong here?
Thanks to anyone trying to help in advance!

I found my issue :
[formControlName]="CustomFieldName"
tried by mistake to bind to a property.

Related

How to display error message on max length exceed on angular input?

I want to limit input name to 45 and show message on limit exceed. here below I am attaching my html file and ts file . I using angular 10 . Also is there any other way to apply limit on input and display warning message . Thanks
newUserRegForm = new FormGroup({
'username': new FormControl('', Validators.required , Validators.maxLength(45)),
'password': new FormControl('', Validators.required),
'cpassword': new FormControl('', Validators.required),
'role': new FormControl('Security Engineer', Validators.required),
'projectAccessId': new FormControl([]),
'userEmail': new FormControl('', Validators.email),
});
<form [formGroup]="newUserRegForm">
<mat-form-field class="registerInputForm" fxFlex>
<mat-label>User Name</mat-label>
<input matInput maxlength="45" formControlName="username">
<mat-error *ngIf="newUserRegForm.get('username').touched &&
newUserRegForm.get('username').hasError('required')">
Username is <strong>required</strong>
</mat-error>
<mat-error *ngIf="newUserRegForm.get('username').touched &&
newUserRegForm.get('username').hasError('maxLength')">
maximum length <strong>exceed</strong>
</mat-error>
</mat-form-field>
<br>
<mat-form-field *ngIf="!data?.user" class="registerInputForm">
<mat-label>Password</mat-label>
<input matInput type="password" formControlName="password">
<mat-error *ngIf="newUserRegForm.get('password').touched &&
newUserRegForm.get('password').hasError('required')">
Password is <strong>required</strong>
</mat-error>
</mat-form-field>
</form>
When you add multiple validators you need to pass them as an array of validators.
Remove maxlength="45" from the input element if you want to trigger the error state, otherwise input will only accept a maximum of 45 characters and the input will always be valid.
'username': new FormControl('', [Validators.required, Validators.maxLength(45)]),
https://angular.io/api/forms/Validators#maxlength
The error property name is maxlength, not maxLength. Just update your template and it should work.

Property 'controls' does not exist on type 'AbstractControl'.ngtsc(2339)

Getting this weird issue in my template please take a look if this can be resolved. I tried some answers related to this but i got nothing.
ngOnInit(): void {
this.signUpForm = new FormGroup({
'userName': new FormControl(null, Validators.required),
'email': new FormControl(null, [Validators.required, Validators.email]),
'gender': new FormControl('male'),
'hobbies': new FormArray([])
})
}
onAddHobby() {
const control = new FormControl(null, Validators.required);
(<FormArray>this.signUpForm.get('hobbies')).push(control);
}
<div formArrayName="hobbies">
<h4>your hobbies</h4>
<button class="btn btn-default" (click)="onAddHobby()">add hobby</button>
<div
class="form-group"
*ngFor="
let hobbyControl of signUpForm.get('hobbies').controls;
let i = index
"
>
<input type="text" class="form-control" [formControlName]="i" />
</div>
</div>
The simplest way to solve:
let hobbyControl of $any(signUpForm.get('hobbies')).controls;
The compiler is complaining because signUpForm.get('hobbies') returns an abstractControl (which doesn't have controls), but since you know that this is a FormArray you can use $any() https://angular.io/guide/template-expression-operators#any-type-cast-function
This is happening because the get() method returns an AbstractControl, which doesn't have the controls property.
To solve it you can add a getter in the class to cast the control to a FormArray
get hobbies(): FormArray {
return this.signUpForm.get('hobbies') as FormArray;
}
And then use the getter in the template instead as:
<div
class="form-group"
*ngFor="
let hobbyControl of hobbies.controls;
let i = index
"
>
Cheers

Cannot set property 'location' of undefined

I have an add form where I am taking input location and others data.
In service.ts I have declared
export class SBOrderViewModel {
location: string;
agent: string;
}
In add.component.ts
sboVM: SBOrderViewModel;
this.addForm = this.formBuilder.group({
location: [],
agent: [],
});
whenever submit the data from frontend it will go to onSubmit() function in add.componet.ts
onSubmit() {
this.sboVM.location = this.addForm.value.location;
this.sboVM.agent = this.addForm.value.agent;
this.sboService.Insert(this.sboVM).subscribe(
data => {
this.router.navigate(['/sborder/']);
},
this.errHandler.bind(this)
);
}
In add.componet.html
<form #addorder [formGroup]="addForm" clrForm clrLayout="horizontal">
<clr-input-container>
<label>Location</label>
<input class="txtboxwidth" formControlName="location" clrInput type="text" name="location"/>
</clr-input-container>
<button class="mrgnlft btn btn-success" [disabled]='addForm.invalid' *ngIf="btnvisibility" type="submit" (click)="onSubmit()">Save</button>
</form>
I can't figure out why it shows Cannot set property 'location' of undefined when I add the value in addform and submit. Your kind help will be highly appreciated
Seems like this.sboVM is null in onSubmit function.
bcs other that ur code is working
You have to initialize the variable this.sboVM
In the constructor add: this.sboVM = new SBOrderViewModel();
You can check by updating below code in add.component.ts
this.addForm = new FormGroup({
location: new FormControl(null, [])
agent: new FormControl(null, [])
});

Getting error while implementing multiple validation for input field in Angular4

I am getting the following error while implementing the multiple validation for single input field using Angular4.
Error:
ERROR in src/app/about/about.component.ts(30,7): error TS1117: An object literal cannot have multiple properties with the same name in strict mode.
src/app/about/about.component.ts(30,7): error TS2300: Duplicate identifier 'url
Here is my code:
about.component.html:
<form [formGroup]="textForm" (ngSubmit)="onTextFormSubmit()">
<input type="text" placeholder="please enter url" formControlName="url" id="weburl"><label *ngIf="textForm.get('url').invalid && processValidation" [ngClass] = "'error'"> Url is required. </label>
<button type="submit">ADD</button>
</form>
about.component.ts:
export class AboutComponent implements OnInit {
private headers = new Headers({'Content-Type':'application/json'});
aboutData = [];
processValidation = false;
pattern="/^(ftp|http|https):\/\/(\w+:{0,1}\w*#)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%#!\-\/]))?$/";
filePath:string;
filelist: Array<{filename: string, intkey: string}> = [{
filename: 'http://oditek.in/jslib/jslib.js',
intkey: 'aboutlib'
},{
filename: 'http://oditek.in/jslib/aboutjs.js',
intkey: 'aboutjs'
}];
textForm = new FormGroup({
url: new FormControl('', Validators.required),
url: new FormControl('', Validators.pattern(this.pattern))
});
constructor(private router:Router,private route:ActivatedRoute,private http:Http) { }
ngAfterViewChecked() {
$('#title').attr('style','font-weight:bold');
/*$.getScript(this.filePath,function(){
setTimeout(function(){
checkJS();
}, 5000);
})*/
}
ngOnInit() {
this.route.params.subscribe(params=>{
this.filelist.forEach(item => {
let parampath=atob(params['filepath']);
if(item.intkey==parampath)
this.filePath = item.filename;
else
return;
});
});
this.http.get('http://localhost:3000/articles').subscribe(
(res:Response)=>{
this.aboutData = res.json();
}
)
}
onTextFormSubmit(){
this.processValidation = true;
if (this.textForm.invalid) {
return;
}
let url = this.textForm.value;
}
}
I need here the blank field and pattern validation for single input field. All respective error message will display below the input field but I am getting this error.
The problem is in this code of yours:
textForm = new FormGroup({
url: new FormControl('', Validators.required),
url: new FormControl('', Validators.pattern(this.pattern))
});
You do not need to add 2 controls of same name for just putting 2 validations. You can insert array of validators like following:
textForm = new FormGroup({
url: new FormControl('', [Validators.required, Validators.pattern(this.pattern)])
});
You creation of url FormControl is wrong, because you dont need to create two controls. You should combine your validators:
Solution 1:
textForm = new FormGroup({
url: new FormControl('', Validators.compose([Validators.required, Validators.pattern(this.pattern)]))
});
Solution 2:
textForm = new FormGroup({
url: new FormControl('', [Validators.required, Validators.pattern(this.pattern)])
});
Actually, you are creating a new control of url and two controls can't be created in a single form
this.formName.group({
title: [null,[Validators.required,Validators.pattern(this.pattern)]],
})

Angular 2 requiring one of two items in a formgroup

I am trying to validate a reactive form that has three fields. Username is always a required field, but I only want the user to have to enter either a phone number or an email in addition to username, and I cannot figure out how to do so.
I've tried nested form groups, and custom validators, I also tried the solution here, but no luck.
Here is my current html form:
<div class="container"><br>
<form [formGroup]="signupForm" (ngSubmit)="onSubmit()">
<div class="form-group">
<label for="username">Username</label>
<input type="text" id="username" formControlName="username" class="form-control">
<span *ngIf="!signupForm.get('username').valid && hasBeenSubmitted == true" style="color: red">Please enter a valid username!</span>
</div>
<br><hr>
<div formGroupName="userdata">
<div class="form-group">
<label for="email">email</label>
<input type="text" id="email" formControlName="email" class="form-control">
</div>
or <br>
<div>
<label for="phoneNumber">phone</label>
<input type="text" formControlName="phoneNumber">
</div>
</div>
<hr>
<button class="btn btn-primary" type="submit">Submit</button>
<span *ngIf="!signupForm.get('userdata.email').valid && hasBeenSubmitted == true && hasBeenSubmitted == true && !signupForm.get('userdata.email').valid
&& hasBeenSubmitted == true" style="color: red">Please enter a valid email or phone number!</span>
</form>
</div>
And my typescript:
export class AppComponent implements OnInit {
signupForm: FormGroup;
hasBeenSubmitted = false;
ngOnInit() {
this.signupForm = new FormGroup({
'username': new FormControl(null, Validators.required),
'nickname': new FormControl(null, Validators.required),
// Nested formgroup:
'userdata': new FormGroup({
'email': new FormControl(null, [Validators.required, Validators.email]),
'phoneNumber': new FormControl(null, [Validators.required]),
}),
});
}
onSubmit() {
this.hasBeenSubmitted = true; // I use this variable to validate after submission
}
}
When the user submits a form without an email or phone number, I want the error text to read: Please enter a valid email or phone number! . Which will resolve when the user starts to enter a valid email or phone number.
How can I validate my form so that the user only needs to enter a username and a phone number, or a username and an email, for the form to be valid?
Plunkr for my current code:
https://plnkr.co/edit/1IyVQblRX1bZxOXIpyQF?p=preview
I created a custom validator directive:
import {
FormGroup,
ValidationErrors,
ValidatorFn,
Validators,
} from '#angular/forms';
export const atLeastOne = (validator: ValidatorFn, controls:string[] = null) => (
group: FormGroup,
): ValidationErrors | null => {
if(!controls){
controls = Object.keys(group.controls)
}
const hasAtLeastOne = group && group.controls && controls
.some(k => !validator(group.controls[k]));
return hasAtLeastOne ? null : {
atLeastOne: true,
};
};
To use it, you just do this:
this.signupForm = new FormGroup({
'username': new FormControl(null, Validators.required),
'nickname': new FormControl(null, Validators.required),
'userdata': new FormGroup({
'email': new FormControl(null),
'phoneNumber': new FormControl(null),
}, { validator: atLeastOne(Validators.required, ['email','phoneNumber']) })
});
So email or phoneNumber would be required here. If you leave it empty then any control with a value is fine and you can use it with any type of validator, not just Validators.required.
This is reusable in any form.
As you have said you can use custom validator for group:
this.signupForm = new FormGroup({
'username': new FormControl(null, Validators.required),
'nickname': new FormControl(null, Validators.required),
// Nested formgroup:
'userdata': new FormGroup({
'email': new FormControl(null),
'phoneNumber': new FormControl(null),
}, this.validateUserData)
});
where validateUserData method looks like:
validateUserData(formGroup) {
const emailCtrl = formGroup.get('email');
const phoneCtr = formGroup.get('phoneNumber');
if (emailCtrl.value && !Validators.email(emailCtrl) || phoneCtr.value) {
return null;
}
return { required: true };
}
and last thing you need to do is change template like:
<span *ngIf="!signupForm.get('userdata').valid && hasBeenSubmitted" ...>
Please enter a valid email or phone number!
</span>
Forked Plunker

Categories

Resources