Cannot set property 'location' of undefined - javascript

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, [])
});

Related

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

Angular5 reactive forms with mailcheck.js

below is HTML code for form
<div class="form-group">
<label for="email">Email</label>
<input type="email" class="form-control"
(blur)="suggestEmail(signupForm.controls['userData'].controls.email.value)"
id="email" formControlName="email">
<span class="help-block" *ngIf="!signupForm.get('userData.email').valid && signupForm.get('userData.email').touched">
please enter a valid email id
</span>
</div>
Below is ts code
constructor(private fb: FormBuilder) {
this.signupForm = this.fb.group({
userData: this.fb.group({
email: [null, [Validators.required, Validators.email]]
})
});
}
ngOnInit() {
}
suggestEmail(email) {
Mailcheck.run({
email: email,
domains: ['gmail.com', 'aol.com', 'hotmail.com', 'yahoo.com', 'rediffmail.com', 'edu', 'msn.com',],
secondLevelDomains: ['domain', 'hotmail'],
topLevelDomains: ["com", "net", "org", "info"],
suggested: function (suggestion) {
console.log(suggestion);
if (suggestion) {
alert(suggestion.full);
console.log(suggestion.full + "dkdjdekjekde")
}
},
empty: function () {
}
});
}
Right now, value of suggestions.full comes in alert if its being called. But I am trying to show suggestions.full in html side, like as a error warning.
Below is link to my stackblitz
stackblitz
To avoid potential problems with access to this within the Mailcheck.run suggested callback, you could save the results of Mailcheck.run, check them and, if appropriate, set an error on your form field.
let check = Mailcheck.run({
email: email,
... other stuff ...
suggested: (suggestion) => {
return suggestion;
},
empty: () => {
return false; // or however you want to handle it...
}
if (check && check.full) {
this.suggestedEmail = check.full;
this.signupForm.get('userData.email').setErrors({ 'has_suggestion': true })
}
// then in your template (using a getter)
<span class="help-block"
*ngIf="f.invalid && f.touched && f.errors?.has_suggestion">
Suggestion: {{suggestedEmail}}
</span>
Please find this stackblitz -- hope it helps!
Instead of using a regular function which will be lost this scope whereas arrow function keeps track of this. Read more about the difference here https://stackoverflow.com/a/34361380/5836034
do something like this
....
suggestion: any;
....
suggestEmail(email) {
Mailcheck.run({
email: email,
domains: ['gmail.com', 'aol.com', 'hotmail.com', 'yahoo.com', 'rediffmail.com', 'edu', 'msn.com',],
secondLevelDomains: ['domain', 'hotmail'],
topLevelDomains: ["com", "net", "org", "info"],
suggested: (suggestion) => {
console.log(suggestion);
if (suggestion) {
alert(suggestion.full);
this.suggestion = suggestion;
console.log(suggestion.full + "dkdjdekjekde")
}
},
empty: function () {
}
});
}
Observe the use of arrow function, to keep track of this scope and also, assigning the value of suggestion to your class variable via
this.suggestion = suggestion
in your template, you can now have access to suggestion like so
<div *ngIf="suggestion">{{suggestion.full}} </div>
Source: https://stackblitz.com/edit/angular-email-checker-bjcrcc

Getting a 'Path Error' with nested forms Array

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.

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)]],
})

Keeping track of added element in an array?

I'm playing around with vue.js and the .vue components, and as newbie, I'm wondering how can I keep track of the element I add in the array.
The situation is the following :
The user add a new element from a form
When he submit, the data are automatically added to a ul>li element, and a POST request is made to the API
When the POST is done, I want to update the specific li with the new data from the server.
The thing is, I can not target the last li because the server can take time to process the request (he do a lot of work), so the user may have added 1, 5, 10 other entries in the meantime.
So how can I do ?
Here's my code so far :
<template>
<form method="post" v-on:submit.prevent="search">
<input type="text" placeholder="Person name" required v-model="name" v-el="nameInput" />
<input type="text" placeholder="Company" required v-model="company" v-el="domainInput" />
<input type="submit" value="Search" class="btn show-m" />
</form>
<ul>
<li transition="expand" v-for="contact in contacts">
<img v-bind:src="contact.avatar_url" width="40px" height="40px" class="cl-avatar" />
<div class="cl-user">
<strong class="cl-name">{{contact.name}} <span class="cl-company">{{contact.company}}</span></strong>
</div>
</li>
</ul>
</template>
<script>
export default {
data () {
return {
contacts: [],
name: null,
company: null
}
},
methods: {
search: function (event) {
this.$http.post('/search', {
name: this.name,
company: this.company
}).then(function (xhr) {
// HERE ! How can I target the exact entry ?
this.contacts.unshift(xhr.data)
})
this.name = ''
this.company = ''
this.contacts.unshift({'name': this.name, 'company': this.company})
},
}
}
</script>
Thank you for your help ! :)
If you know that the name and company fields are unique you could search through the array to find it... otherwise you can just wait to append it to the array until the return function:
search: function (event) {
this.$http.post('/search', {
name: this.name,
company: this.company
}).then(function (xhr) {
this.contacts.unshift(xhr.data)
})
this.name = ''
this.company = ''
},
I finally found a working solution : I use a component instead of <li /> for each entries, and manage the state of these inside the component :
<ul>
<contact-entry v-for="contact in contacts" v-bind:contact="contact"></contact-entry>
</ul>
That way, when I add a new entry in the array (described above), a new instance of the component contact-entry is made.
Inside that component, I did the following :
<script>
export default {
props: ['contact'],
created: function () {
if (this.contact.id === undefined) { // If it's a new contact
this.$http.post('search/name', { // I do the post here
name: this.contact.name,
domain: this.contact.company.name
}).then(function (xhr) {
this.contact = xhr.data // This will update the data once the server has replied, without hassle to find the correct line
})
}
}
}
</script>
That's it ! :) In the parent's component, I removed the xhr request and simplified the method to :
<script>
export default {
data () {
return {
contacts: [],
name: null,
company: null
}
},
methods: {
search: function (event) {
this.name = ''
this.company = ''
this.contacts.unshift({'name': this.name, 'company': this.company})
}
}
}
</script>

Categories

Resources