I have this inside a component:
private formBuilder: FormBuilder
...
signupForm: FormGroup;
...
this.signupForm = this.formBuilder.group({
'name': [null, Validators.required],
'account': this.formBuilder.group({
'email': [null, [Validators.required, ...]],
'confirm_email': [null, Validators.required],
}, {validator: ValidationService.emailMatcher}),
'password': [null, [Validators.required,...]]
});
And I want to set the value for the email field. I tried this, but no luck:
this.signupForm.patchValue({'email': 'myvalue#asd.com'});
But the value is nested, so whats the sintax in this case? I also tried:
this.signupForm.patchValue({'account.email': 'myvalue#asd.com'});
Also searched here:
https://angular.io/docs/ts/latest/api/forms/index/FormGroup-class.html#!#patchValue-anchor
Thanks
Try this:
this.signupForm.patchValue({account:{email: 'myvalue#asd.com'}});
Another solution is:
(<FormGroup>this.signupForm.controls['account']).controls['email'].patchValue('myvalue#asd.com');
Sorry for bad indentation.
Related
I am trying to integrate Tap payments on my Flutter mobile application.
As per Tap's documentation, I need to pass src_card for VISA/MasterCard and src_kw.knet for KNET payment gateway. The code below is only accepting one parameter.
Map<String, dynamic> getOrderParams() {
var cartModel = Provider.of<CartModel>(context, listen: false);
return {
'amount': cartModel.getTotal(),
'currency': kAdvanceConfig.defaultCurrency?.currencyDisplay,
'threeDSecure': true,
'save_card': false,
'receipt': {'email': false, 'sms': true},
'customer': {
'first_name': cartModel.address?.firstName ?? '',
'last_name': cartModel.address?.lastName ?? '',
'email': cartModel.address?.email ?? '',
},
'source': {'id':'src_card'}, <--- HERE
'post': {'url': kRedirectUrl},
'redirect': {'url': kRedirectUrl}
};
}
How can I pass both src_card and src_kw.knet here? I get this error when I add another param:
The literal can't be either a map or a set because it contains at
least one literal map entry or a spread operator spreading a 'Map',
and at least one element which is neither of these.
Try src_all in place of card
'source': {'id':'src_all'},
I'm using ag-grid in Angular9 project. I'm using Transactions to do CRUD operations in grid when my backend request resolve. I need to provide RowNodeId myself, i dont want to use object-references as i have large data set.
Thing is, i've provided the ID and i can add/update item in the grid but i'm unable to delete the item. In Doc it mentions, you only need to provide id to remove the item but i'm getting the following error.
Here's the code.
class HostAppListPage
{
#ViewChild('agGrid', {static: true}) grid:AgGridAngular;
constructor()
{
}
ngOnInit()
{
this.grid.getRowNodeId = (data) => {
return data.entityId;
};
this.columns = [
{headerName: 'App Name', field: 'name', rowDrag: true, headerCheckboxSelection: true, checkboxSelection: true},
{headerName: 'App Id', field: 'id'},
{headerName: 'Compatibility', field: COMPATIBILITY'},
{headerName: 'Creation', field: 'createdAtToString'},
{headerName: 'Last Update', field: 'updatedAtToString'}
];
}
deleteRow()
{
let ids = this.gridApi.getSelectedNodes()
// .map((row) => {
// return {id: row.entityId}
// return row.entityId;
// });
console.log(ids);
this.grid.api.applyTransaction({remove: ids});
}
I tried both with and without map statement, nothing worked
but my Add and Update works fine.
Replace map with following code.
.map((row) => {
return {entityId: row.data.entityId};
});
it should be the the same field (entityId) which i set in getRowNodeId function.
In a typical situation, where one does not define a getRowNodeId, one should be able to do:
const removeData: any[] = [{id: rowNode0.id}, {id: rowNode1.id}, ...];
applyTransaction({remove: removeData});
where rowNode0, rowNode1, etc. are the nodes you want to remove.
However when you provide your own getRowNodeId callback, ag-grid will fetch the id's by applying your callback on the data you provided. Therefore, the name(s) in the data must match those used in your callback. That's why return {id: row.entityId} doesn't work, but return {entityId: row.entityId} does.
In other words, if one defines:
this.grid.getRowNodeId = (data) => {
return data.column1 + data.column5 + data.column2;
};
Then one would need to provide
const removeData: any[] = [
{column1: 'a1', column2: 'b1', column5: 'c1'},
{column1: 'a2', column2: 'b2', column5: 'c2'},
{column1: 'a3', column2: 'b3', column5: 'c3'},
];
so that ag-grid would have all the names it needs to find the id's via the given getRowNodeId.
I have created one React app. For data fetching, I used axios. My app works fine as expected. But in my terminal, I am getting warning like this Line 34:6: React Hook useEffect has a missing dependency: 'props.match.params.id'. Either include it or remove the dependency array react-hooks/exhaustive-deps. I don't want to use // eslint-disable-next-line react-hooks/exhaustive-deps. Is there any alternative solution?
useEffect(() => {
axios
.get("http://localhost:5000/students/" + props.match.params.id)
.then(response => {
setState({
name: response.data.name,
birthday: response.data.birthday,
address: response.data.address,
zipcode: response.data.zipcode,
city: response.data.city,
phone: response.data.phone,
email: response.data.email
});
})
.catch(function(error) {
console.log(error);
});
}, []);
If you don't want to disable the eslint rule, you need to follow it, simply add the prop to your dependency array:
useEffect(() => {
axios
.get("http://localhost:5000/students/" + props.match.params.id)
.then(response => {
setState({
name: response.data.name,
birthday: response.data.birthday,
address: response.data.address,
zipcode: response.data.zipcode,
city: response.data.city,
phone: response.data.phone,
email: response.data.email
});
})
.catch(function(error) {
console.log(error);
});
}, [props.match.params.id]);
This means that if the id changes, your effect will be unmounted and called again, which seems to make sense, considering the match.params.id is used inside your effect.
In my angular 2 app, I have an edit assignment component which loads when user clicks on edit button. It displays a form and fills all form controls with already existing values from firebase database which user can then edit. It loads all the values in the form controls when I click the edit button for the first time. Then if I go back or navigate to any other link and then click on the edit button again the form controls do not patch values from firebase database.
The images below will help you understand the problem better:
I click on the edit button first time everything works fine
Then if I go back to some other link and then return by clicking the edit button again the form does not patch form controls with values from firebase database.
I am validating my form like this
constructor(
private _routeParams: ActivatedRoute,
private _db: AngularFireDatabase,
private _fb: FormBuilder,
private _uploadService: UploadService,
private _getAsnService: GetAssignmentService,
private _editAsnSvc: EditAssignmentService,
) {
console.log("in constructor");
this.validate();
}
ngOnInit() {
console.log("in init");
this.getRouteParams();
this.assignment = this._getAsnService.getAssignment(this.asnDetailKey); // this.assignment is FirebaseObjectObservable retrieved from firebase DB
this.setInputValues();
this.getCourses();
this.validate();
}
validate() {
this.form = this._fb.group({
course: ['', Validators.compose([Validators.required])],
batch: ['', Validators.compose([Validators.required])],
subject: ['', Validators.compose([Validators.required])],
name: ['', Validators.compose([Validators.required])],
description: ['', Validators.compose([Validators.required])],
dueDate: ['', Validators.compose([Validators.required])]
});
this.today = new Date().toJSON().split('T')[0];
}
setInputValues() {
this.assignment.subscribe(asnDetails => {
console.log("setting values"); // <----- These are the values you see in console
this._assignment = asnDetails;
console.log(this._assignment); // <----- _assignment contains all values but form controls are unable to patch them
this.form.get('course').patchValue(this._assignment.course);
this.form.get('batch').patchValue(this._assignment.batch);
this.form.get('subject').patchValue(this._assignment.subject);
this.form.get('name').patchValue(this._assignment.AsnName);
this.form.get('description').patchValue(this._assignment.AsnDesc);
this.form.get('dueDate').patchValue(this._assignment.dueDate);
this.batches = this._db.list('/batches/' + this._assignment.course);
});
}
Thanks
* Edited *
I removed the setInputValues method and did the validation inside the validateForm method (i changed name from validate to validateForm) by passing asnDetails to it as told by #developer033
ngOnInit() {
this.getRouteParams();
this.assignment = this._getAsnService.getAssignment(this.asnDetailKey);
this.assignment.subscribe(asnDetails => this.validateForm(asnDetails));
this.getCourses();
}
validateForm(asnDetails) {
this.form = this._fb.group({
course: [asnDetails.course, Validators.compose([Validators.required])],
batch: [asnDetails.batch, Validators.compose([Validators.required])],
subject: [asnDetails.subject, Validators.compose([Validators.required])],
name: [asnDetails.AsnName, Validators.compose([Validators.required])],
description: [asnDetails.AsnDesc, Validators.compose([Validators.required])],
dueDate: [asnDetails.dueDate, Validators.compose([Validators.required])]
});
this.today = new Date().toJSON().split('T')[0];
this.batches = this._db.list('/batches/' + asnDetails.course);
}
I also created a initForm method and call it from constructor to initialize form.
initForm() {
this.form = this._fb.group({
course: ['', Validators.compose([Validators.required])],
batch: ['', Validators.compose([Validators.required])],
subject: ['', Validators.compose([Validators.required])],
name: ['', Validators.compose([Validators.required])],
description: ['', Validators.compose([Validators.required])],
dueDate: ['', Validators.compose([Validators.required])]
});
}
I think thats the cleaner way to validate model driven forms dynamically.
Your validate() method actually is wrong. It is initialising the form with default values and with validators which get executed automatically. The name validate() is misleading. In your case you create a new form with this._fb.group() everytime and you loose all the former values. The first time its just working because the request takes some time and in the meantime your validate() aka initializeForm() method did run. I guess in all other cases the request may is cached and so the setInputValues is called before your validate method. Just move the call to validate() before calling the asnService and you should be good. Greetings Chris
I have the following form in Angular created with FormBuilder:
constructor(private fb: FormBuilder) {
this.myForm = fb.group({
'name': ['', [Validators.required],
'surname': ['', [Validators.required],
'email': ['', [validateEmail]],
'address': fb.group({
'street': [''],
'housenumber': [''],
'postcode': ['']
}, { validator: fullAddressValidator })
});
}
Does exist a way to programmatically append new fields such as FormControl or new FormGroup to myForm ?
I mean if I want to add new fields on demand or on some conditions, how to add items to the same form that is created the first time in the constructor?
You can use addControl method of FormGroup class as per documentation
So you can do as below :
this.myForm.addControl('newcontrol',[]);
To add upon what #ranakrunal9 said.
If you would like to use validators with addControl do the following:
this.myForm.addControl('newControl', new FormControl('', Validators.required));
Just remember to add the following import
import {FormControl} from "#angular/forms";
Reference to addControl: https://angular.io/api/forms/FormGroup#addControl
Reference to FormControl: https://angular.io/api/forms/FormControl
In my opinion, you could just use an intermediate variable for this purpose. Take a look at the next example:
constructor(private fb: FormBuilder) {
let group = {
'name': ['', [Validators.required]],
'surname': ['', [Validators.required]],
'email': ['', [Validators.required]]
};
let middlename = true;
if(middlename) {
group['middlename'] = ['', [Validators.required]];
}
this.myForm = fb.group(group);
}
Also, it would a better idea to transfer a form initiation in ngOnInit hook, instead of component constructor.
I had the same issue, but since I already have a empty FormGroup {} inside the main FormGroup I was able to append FormControls like this:
(this.myForm.get("form_group_name") as FormGroup).addControl("item1", new FormControl("default val"));