Angular reactive form cannot find control with path - html

Currently, I'm creating a reactive form:
this.entryService.getEntryObservable(weekNumber).subscribe(entries => {
this.entriesArr = entries;
this.entriesReceived = true;
this.populateEntries();
}, error => {
this.entriesErrMsg = error;
});
populateEntries() {
this.entriesForm = this.fb.group({
entries: this.fb.array(this.entriesArr.map(entry => this.fb.group({
type: [entry.type, Validators.required],
hours: [entry.hours, Validators.required],
tasks: [entry.tasks, Validators.required],
}, {updateOn: 'blur'})))
});
}
Now I've added a getter which returns the entries:
get entries() {
return (this.entriesForm.get('entries') as FormArray).controls;
}
This getter is called inside my HTML:
<form [formGroup]="entriesForm" *ngIf="entriesReceived">
<div *ngFor="let entry of entries; let i = index;" [formGroupName]="i">
<mat-form-field appearance="fill">
<mat-label>Stunden...</mat-label>
<input matInput type="number" placeholder="8" min="1" step="1" formControlName="hours">
<span matSuffix>h</span>
</mat-form-field>
.....
</div>
</form>
But somehow I'm getting this error here and I really don't know what I'm doing wrong...
Error: Cannot find control with path: '4 -> hours'
When I log the entries return value I'm getting this structure in the console:
Any suggestions?

Related

ERROR TypeError: can't assign to property "validator" on "12345": not an object

I want to build a pre filled form, as of now I am getting this error when i try to display the form page. I have tried various solutions that was given but that doesn't seem to work here.
My hardwareRequest.ts
hardwareReviewForm: FormGroup;
assetSerialNumber = new FormControl('');
modelType = new FormControl('');
ngOnInit(): void {
this.data = []
this.service.loadRequestData(this.requestId).subscribe(
(response: any) => {
this.data = response
console.log(this.data)
this.assetSerialNumber = this.data.assetSerialNumber
this.modelType = this.data.modelType
},
(error) => {
}
)
}
My HTML file
<form class="example-container" [formGroup]="hardwareReviewForm" (ngSubmit)="onFormSubmit()">
<div class="ds-col-12" style="margin-bottom: 10px;">
<div class="ds-col-6">
<mat-form-field appearance="outline">
<mat-label>Asset Serial Number: </mat-label>
<input formControlName="assetSerialNumber" readonly matInput type="text">
</mat-form-field>
</div>
<div class="ds-col-6">
<mat-form-field appearance="outline">
<mat-label>Part No./Model Type: </mat-label>
<input formControlName="modelType" readonly matInput type="text">
</mat-form-field>
</div>
</div>
</form>
You can make a 'View Model' of your fields and then reset your form with it.
export class testVm {
assetSerialNumber : number;
modelType : string;
}
var model: testVm = this.data;
this.hardwareReviewForm.reset(model)
Or if you want to assign value separately you should act like this:
this.hardwareReviewForm.controls["assetSerialNumber"].reset(this.data.assetSerialNumber.toString())
Firstly, you have to define form controls inside formGroup;
hardwareReviewForm = new FormGroup({
assetSerialNumber = new FormControl('');
modelType = new FormControl('');
});
Secondly, you set the values to controls like below;
this.hardwareReviewForm.get('assetSerialNumber').setValue(this.data.assetSerialNumber);
I figured this out.. It was a silly mistake of .setValue for form controls.
setting my value like below works fine.
this.Number.setValue(this.data.Number)
this.Type.setValue(this.data.Type)

Update #f="ngForm" variable after editing profile

I`m using Angular 7 and reactive forms to create Edit Profile page.
I have all my input values filled in from database. If I want to change first name and last name for example, clicking the update button, everything is looking fine, all fields are updated.
The problem is that if I want to update again only the first name, after clicking the update button, last name has intial value.
So, the problem is that my variable #f="ngForm" is keeping old values (first values) and somehow after update process, #f variable has again first values.
<form [formGroup]="patientEditForm" #f="ngForm" (ngSubmit)="editPatientProfile(f)">
editPatientProfile(f: NgForm ) {
this.submitted = true;
this.isRequesting = true;
this.errors = '';
if (f.valid) {
this.userService.editPatientProfile(this.patientId,
this.patient.nin,
f.value.firstName,
f.value.lastName,
this.email,
f.value.password,
f.value.city,
f.value.country,
f.value.birthdate,
f.value.phoneNumber)
.finally(() => this.isRequesting = false)
.subscribe(
result => {
if (result) {
this.router.navigate(['/patient/account']);
localStorage.setItem('displayMessage1', "true");
window.location.reload();
}
},
errors => this.errors = errors);
}
}
<input type="email" value="{{patient.email}}" disabled class="form-control mb-2 mr-sm-2 mb-sm-0">
this.patientEditForm = this.formBuilder.group({
lastName: ['Test', [Validators.required, Validators.minLength(3), Validators.maxLength(30), Validators.pattern("[a-zA-Z]+")]],
firstName: ['Test', [Validators.required, Validators.minLength(3), Validators.maxLength(30), Validators.pattern("[a-zA-Z]+")]],
phoneNumber: ['0745119974', [Validators.required, Validators.pattern("[0-9]+")]],
birthdate: ['1996-02-10', [Validators.required,this.validateDOB.bind(this)]],
city: ['Iasi', [Validators.required, Validators.minLength(3), Validators.maxLength(30), Validators.pattern("[a-zA-Z]+")]],
password: ['', [Validators.required, Validators.minLength(6), Validators.maxLength(35), this.validatePasswordConfirmation.bind(this)]],
country: ['Romania', [Validators.required, Validators.minLength(3), Validators.maxLength(30), Validators.pattern("[a-zA-Z]+")]]
});
Finally, I solved the problem by setting the new proprieties in subscrive event:
private getPatient() {
this.userService.getPatient(this.patientId)
.subscribe((patient: PatientProfile) => {
this.patient = patient;
this.patientEditForm.controls['lastName'].setValue(patient.lastName);
this.patientEditForm.controls['firstName'].setValue(patient.firstName);
this.patientEditForm.controls['phoneNumber'].setValue(patient.phoneNumber);
this.patientEditForm.controls['birthdate'].setValue(patient.birthdate);
this.patientEditForm.controls['city'].setValue(patient.city);
this.patientEditForm.controls['country'].setValue(patient.country);
},
errors => this.errors = errors
);

Angular 6: Cannot read property 'controls' of undefined - reactive forms

I am building a simple dashboard in Angular 6. I am using form builder to create my form that looks like this:
campaignForm = this.formBuilder.group({
name: ['', Validators.required],
countries: this.formBuilder.array([
this.formBuilder.control('')
]),
apps: this.formBuilder.array([
this.formBuilder.control('')
])
});
I would like to be able to save that form and save it via api to the database. However I keep getting 'Cannot read property 'controls' of undefined' that is pointing to the line in html. I've been following a guide in angular documentation on how to build reactive forms.
Here's the relevant TS code:
campaign.model.ts
export class Campaign {
id: string;
name: string;
countries?: any;
apps?: any;
}
add-campaign.component.ts
campaign: Campaign;
campaignForm = this.formBuilder.group({
name: ['', Validators.required],
countries: this.formBuilder.array([
this.formBuilder.control('')
]),
apps: this.formBuilder.array([
this.formBuilder.control('')
])
});
constructor(public campaignsService: CampaignsService, public route: ActivatedRoute, private formBuilder: FormBuilder) { }
ngOnInit() {
this.route.paramMap.subscribe((paramMap: ParamMap) => {
if (paramMap.has('campaignId')) {
this.mode = 'edit-campaign';
this.campaignId = paramMap.get('campaignId');
this.campaignsService.getCampaign(this.campaignId)
.subscribe(campaignData => {
this.campaign = {
id: campaignData._id,
name: campaignData.name,
countries: campaignData.countries,
apps: campaignData.apps
};
this.campaignForm.setValue({
'name': this.campaign.name,
'countries': this.campaign.countries
});
});
} else {
this.mode = 'add-campaign';
this.campaignId = null;
}
});
get country() {
return this.campaignForm.get('countries') as FormArray;
}
get app() {
return this.campaignForm.get('apps') as FormArray;
}
addCountry() {
this.campaign.countries.push(this.formBuilder.control(''));
}
addApp() {
this.campaign.apps.push(this.formBuilder.control(''));
}
add-campaign.component.html
<form [formGroup]="campaignForm" (ngSubmit)="onSaveCampaign($event)">
<label>Name</label>
<div>
<input type="text" formControlName="name" placeholder="name" required>
</div>
<div formArrayName="countries">
<h3>Country</h3>
<button type="button" (click)="addCountry()">Add Country</button>
<div *ngFor="let country of countries.controls; let i=index">
<label>
Country:
</label>
<input type="text" [formControlName]="i">
</div>
</div>
<div formArrayName="apps">
<h3>App</h3>
<button type="button" (click)="addApp()">Add App</button>
<div *ngFor="let app of apps?.controls; let i=index">
<label>
App
</label>
<input type="text" [formControlName]="i">
</div>
</div>
<button mat-raised-button color="primary" type="submit" [disabled]="!campaignForm.valid">Save campaign</button>
<button mat-raised-button color="primary" type="button" class="button-margin-left" routerLink="/">Go back</button>
</form>
the error seems to be pointing to this line:
<div *ngFor="let country of countries.controls; let i=index">
Does anyone have any idea why is this happening? It seems like Angular cannot access countries property, but I just do not know how to get around this. Any help would be appreciated.

post empty value from autocomplete material typescript

I want to post data from autocomplete material.
My ts code, like this. I used registerUserForm formgroup.
export class AddUserFormComponent implements OnInit {
countryes: Country[];
registerUserForm: FormGroup;
filteredOptionsCountry: Observable<Country[]>;
myControlCountry: FormControl = new FormControl();
constructor(private fb: FormBuilder,
private router: Router,
private cs: CountryService)
{
this.registerUserForm = new FormGroup({
'username': new FormControl(),
'email': new FormControl(),
'country_id': new FormControl(),
});
}
ngOnInit() {
this.registerUserForm = this.fb.group({
'username': ['', Validators.compose([Validators.required, Validators.minLength(5)])],
'country_id': ['', Validators.required],
'email': ['', [Validators.required, ValidationService.emailValidation]],
});
this.filteredOptionsCountry = this.myControlCountry.valueChanges.pipe(
startWith(''),
map(val => this.filterCountry(val))
);
this.cs.getAllCountry().subscribe(
countryes => {
this.countryes = countryes.map((country) => {
return new Country(country);
});
}
);
}
onRegisterUser() {
this.loading = true;
this.invalidInputs = true;
let newUser = new User(
this.registerUserForm.value
);
this.userService.createUser(newUser).subscribe(
);
}
onCancel() {
this.router.navigate(['/main/users']);
}
//Country
filterCountry(val: string): Country[] {
if (val) {
let filterValue = val.toLowerCase();
console.log(this.countryes)
return this.countryes.filter(country => country.name.toLowerCase().startsWith(filterValue));
}
return this.countryes;
}
}
my html code. In this code i have 3 parameters, only email and username i can post, country_id post empty
<form [formGroup]="registerUserForm" (ngSubmit)="onRegisterUser()" class="col s12" materialize>
<div class="row">
<div class="input-field col s12">
<input formControlName="username" id="username" type="text" class="validate" placeholder="Enter Username" minlength="3" maxlength="20"
required="" [ngClass]="{invalid: invalidInputs}">
</div>
</div>
<div class="row">
<div class="input-field col s12">
<input formControlName="email" id="email" type="email" class="validate" placeholder="Enter Email" required="" aria-required="true"
[ngClass]="{invalid: invalidInputs}">
</div>
</div>
<!-- Autocomplete Country Material-->
<input formControlName="country_id" id="country_id" matInput placeholder="Select Country" aria-label="State" [matAutocomplete]="auto"
autoActiveFirstOption [formControl]="myControlCountry">
<mat-autocomplete #auto="matAutocomplete">
<mat-option *ngFor="let country of filteredOptionsCountry | async" [value]="country.name">
{{ country.name }}
</mat-option>
</mat-autocomplete>
<!-- End Autocomplete Country -->
<div id="register_user_button_container" class="row">
<button id="register_user_button" type="submit" class="btn waves-effect waves-light">
Register
</button>
<button id="cancel_button" (click)="onCancel()" class="btn waves-effect waves-light grey lighten-4 black-text">
Cancel
</button>
</div>
</form>
Can you suggest me, how to used this FormControl inside registerUserForm ? Or, something solution.
Your code is litteral chaos.
First, group everything in a single form.
registerUserForm: FormGroup;
Then, instantiate your form only once, you don't need to do it more.
constructor() {
this.registerUserForm = this.fb.group({
username: ['', [Validators.required, Validators.minLength(5)]],
country_id: ['', Validators.required],
email: ['', [Validators.required, ValidationService.emailValidation]],
myControlCountry: ''
});
}
Next, use a getter to get your countries. (This is one of the many ways)
countries: Country[];
get filteredCountries() {
const query = this.registerUserForm.get('country_id').value;
return query ?
this.countries.filter(c => c.name.toLowerCase().includes(query.toLowerCase)) :
this.countries;
}
Now you must bind it to your HTML :
<mat-option *ngFor="let country of filteredCountries" [value]="country.name">
{{ country.name }}
</mat-option>

how to get a specific field value from an object retrieved and bind it to a property in the component TypeScript

Hello i have a type script code that populate options from a back end service ,Now how to perform 2 way data binding on or
,And how to get a specific field value from the object retrieved
for Example the Objects i retrieved each one of them is in json format like this :
countryCode:"TUR"
countryId:185
countryName:"Turkey"
countryPhoneCode:"90"
__proto__:Object
my html is like this :------
<div class="form-group ">
<label class="control-label" for="countryCode">Country</label>
<select class="form-control" id="countryCode"formControlName="countryCode">
<option *ngFor="let country of countryList"
[attr.value]="country.countryCode" [selected]="country.countryCode === viewCountryCode">
{{country.countryName}}</option>
</select>
</div>
here is some of my type script:---
registrationForm: FormGroup;
username: AbstractControl;
useremail: AbstractControl;
commercialWebSiteLink: AbstractControl;
corporateWebSiteLink: AbstractControl;
countryCode: String = "jo";
viewCountryCode: string = "jo";
createSignupForm() {
this.registrationForm = this.builder.group({
username: ['', Validators.compose([
Validators.required,
UserNameValidator.userNameRange,
UserNameValidator.OnlyAlphabets
])],
useremail: ['', Validators.compose([
Validators.required,
EmailValidator.mailFormat,
EmailValidator.domainCheckFormat,
EmailValidator.mailLength,
EmailValidator.specialCharacters
])],
countryCode: [''],
commercialWebSiteLink: ['', Validators.compose([
Validators.required,
UrlValidator.urlFormat,
])],
corporateWebSiteLink: ['', Validators.compose([
Validators.required,
UrlValidator.urlFormat,
])],
merchantType: ['PSP']
});
this.username = this.registrationForm.controls['username'];
this.useremail = this.registrationForm.controls['useremail'];
this.commercialWebSiteLink = this.registrationForm.controls['commercialWebSiteLink'];
this.corporateWebSiteLink = this.registrationForm.controls['corporateWebSiteLink'];
this.regestrationErrorMessage = " ";
}
submitsignup(RegistrationForm: any) {
if (!RegistrationForm.errors && RegistrationForm.valid) {
if ((<HTMLInputElement>document.getElementById("termsandConditons")).checked) {
this.isAcceptTerms = false;
} else {
this.isAcceptTerms = true;
}
this.homeService.signUpMarchent(RegistrationForm).subscribe(
response => {
console.log(response);
if (response.success) {
this.signUpDone == true;
} else {
this.regestrationErrorMessage = this.translate.instant('MerchantRegistration.' + response.code);
if (this.regestrationErrorMessage == '') {
this.regestrationErrorMessage = this.translate.instant('MerchantRegistration.errGeneralError');
}
}
},
error => {
this.regestrationErrorMessage = this.translate.instant('MerchantRegistration.errGeneralError');
}
);
}
}
Now i want in my type script to retrieve Country Id from the object i retrieved , And I want to save it in a type script variable when i submit the form ,so i can then submit it to the back end instead of country code
Any Help will please ,
this is how i solved it
<div class="form-group ">
<label class="control-label" for="countryId">Country</label>
<select class="form-control" id="countryId" formControlName="countryId">
<option *ngFor="let country of countryList" [attr.value]="country.countryId" [selected]="country.countryCode === viewCountryCode">
{{country.countryName}}</option>
</select>
</div>
I made a new form control named in the type script class ,countryId: 1 in the createSignupForm().