I want to create a dynamic form with form array . When I click this (click)="AddInfoName()" it add form .
I am using this code in html :
<form class="form-line" [formGroup]="addinfoForm" (ngSubmit)="AddRole()">
<div formArrayName="infoName">
<div class="description" *ngFor="let name of InfoFormGroup.controls; let NameIndex=index" [formGroupName]="NameIndex">
<div [formGroupName]="i" class="row">
<label class="form-line"> نام : </label>
<input style="margin-right: 50px;" class="form-line" pInputText id="pFaName" formControlName="infoName">
<app-filederrors [form]="addinfoForm"
field="getInfoFormGroup(NameIndex)"
nicename="نام">
</app-filederrors>
</div>
</div>
</div>
</form>
And using this code in ts file :
addinfoForm:FormGroup;
infoNameList:FormArray;
infoModel:Productdetail;
constructor(private fb:FormBuilder,private router:Router,private tokenService:TokenstoreService) { }
ngOnInit() {
this.infoNameList = this.fb.array([]);
this.InfoForm();
}
/**
* AddInfoForm
*/
public InfoForm() {
this.addinfoForm=this.fb.group({
infoName:this.fb.array([this.CreateInfoName()])
})
this.infoNameList=this.addinfoForm.get('infoName') as FormArray;
}
get InfoFormGroup(){
return this.addinfoForm.get('infoName') as FormArray;
}
public CreateInfoName():FormGroup{
return this.fb.group({
infoName:['',Validators.compose([Validators.required])]
});
}
public AddInfoName(){
this.infoNameList.push(this.CreateInfoName());
console.log('sdkjfghjkdfgh')
}
public RemoveInfoName(index:number){
this.infoNameList.removeAt(index);
}
getInfoFormGroup(index:number):FormGroup{
const formGroup=this.infoNameList.controls[index] as FormGroup;
return formGroup;
}
AddInfo(){
console.log('in form ==>',this.addinfoForm.value)
}
I have tow problem with this code :
1 - when I create a new form it show me this Error :
Error: Cannot find control with path: 'infoName -> 0 -> '
2 - return EmptyArray. I create 5 Form but when I click for add data it show me empty
`infoName: Array(5)
0: {infoName: ""}
1: {infoName: ""}
2: {infoName: ""}
3: {infoName: ""}
4: {infoName: ""}`
Whats the problem ? How can I solve problems?
remove the unnecessary [formGroupName]
should be like this
<form class="form-line" [formGroup]="addinfoForm" (ngSubmit)="AddRole()">
<div formArrayName="infoName">
<div class="description" *ngFor="let name of InfoFormGroup.controls; let NameIndex=index" [formGroupName]="NameIndex">
<div class="row">
<label class="form-line"> نام : </label>
<input style="margin-right: 50px;" class="form-line" pInputText id="pFaName" formControlName="infoName">
<app-filederrors [form]="addinfoForm" field="getInfoFormGroup(NameIndex)" nicename="نام">
</app-filederrors>
</div>
</div>
</div>
</form>
Related
Im new to Angular and I can't figure out whats going on here.
I have a MVC Controller which gives me the correct value such as {PostalContactPerson : jeff}
however my Angualar view does not recognise the value on page load in the input box.
How can i get the value into the textbox please? Im perplexed why it's 'blank' when the other values are displayed from the same Form Group.
Form.component.ts
export class FormComponent implements OnInit {
data: any = null;
this.arService.get(id, true)
.subscribe(data => {
this.loading = false;
this.ar = data;
this.attachments = this.ar.attachments.filter(e => e.type == Enums.AttachmentType.Normal);
**this.data = this.ensureData(data.formData);
this.ar.formData = this.data;**
this.stationInformationForm = formBuilder.group({
"businessNumbersGroup": formBuilder.group({
"acn": [this.data.acn],
"icn": [this.data.icn],
"postalcontactperson": [this.data.postaladdress],
}, ),
});
}
ensureData(data: any): any {
if (data == null) {
data = {};
}
if (!data["postalcontactperson"]) {
data["postalcontactperson"] = { state: "" };
}
form.component.html
<div [formGroup]="stationInformationForm.controls['businessNumbersGroup']">
<div class="row">
<div class="col-sm-6">
<div class="form-group">
<label>ACN</label>
<div class="form-description">Specify if applicable</div>
<input type="text" [ngClass]="{'has-error': !stationInformationForm.controls['businessNumbersGroup'].valid && (stationInformationForm.controls['businessNumbersGroup'].controls['acn'].touched || workflowSections[0].submitted)}" formControlName="acn" [(ngModel)]="data.acn"
class="form-control" />
<hr/>
</div>
<div class="form-group">
<label>postalcontactperson</label>
<div class="form-description">Specify if applicable</div>
<input type="text" [ngClass]="{'has-error': !stationInformationForm.controls['businessNumbersGroup'].valid && (stationInformationForm.controls['businessNumbersGroup'].controls['PostalContactPerson'].touched || workflowSections[0].submitted)}" formControlName="PostalContactPerson"
[(ngModel)]="data.postalcontactperson" class="form-control" />
</div>
<hr/>
</div>
</div>
</div>
MVC Model
public static AnnualReturnModel Create(AnnualReturn annualReturn)
{
return new AnnualReturnModel
{
Id = annualReturn.Id,
FormData = annualReturn.FormData,
PostalContactPerson = annualReturn.FormData.PostalContactPerson,
}
}
MVC Form Data
public class AnnualReturnFormData
{
public int? ActiveSectionIndex { get; set; }
#region Station Information
public string LesseeNames { get; set; }
//Postal Address
public string PostalContactPerson { get; set; }
}
json result of above:
{"ActiveSectionIndex":0,"LesseeNames":"aaa","PostalContactPerson":"aa","PostalPosition":"aa","PostalEmail":"aa","PostalPhone":"aa","StationContactPerson":"aaa"}
debugging description here
On page load, my ACN is shown in the textbox but the PostalContactPerson is not. why?
When I put an alert on the site, the contact person does not show my value.
alert(this.data.acn); //shows me a value of 22222
alert("contact person=" + this.data.postalcontactperson); //shows undefined
Any suggestions please? what am I missing, the JSON value is shown correctly when i check the database.
Any suggestions are Much appreciated. what am i missing with the ngModel?
Ive updated the code to the below:
form.component.html
<div [formGroup]="stationInformationForm.controls['postalAddressGroup']">
<div class="row">
<div class="col-sm-6">
<div class="form-group">
<label>Contact Person</label>
<input type="text" formControlName="postalcontactperson"class="form-control" value={{annualReturn.postalcontactperson}} /> <!--value={{annualReturn.postalcontactperson}}-->
</div>
<div class="form-group">
<label>Position</label>
<input type="text" formControlName="postalposition" class="form-control" />
<div class="validation-error" *ngIf="!stationInformationForm.controls['postalAddressGroup'].valid && (stationInformationForm.controls['postalAddressGroup'].get('postalposition').touched || workflowSections[0].submitted)">You must specify Position</div>
</div>
</div>
<div class="row">
<div class="col-sm-6">
<div class="form-group">
<label>Email</label>
<input type="text" formControlName="postalemail" class="form-control" />
<div class="validation-error" *ngIf="!stationInformationForm.controls['postalAddressGroup'].valid && (stationInformationForm.controls['postalAddressGroup'].get('postalemail').touched || workflowSections[0].submitted)">You must specify email</div>
</div>
<div class="form-group">
<label>Phone</label>
<input type="text" formControlName="postalphone" class="form-control" />
<div class="validation-error" *ngIf="!stationInformationForm.controls['postalAddressGroup'].valid && (stationInformationForm.controls['postalAddressGroup'].get('postalphone').touched || workflowSections[0].submitted)">You must specify phone</div>
</div>
</div>
</div>
</div>
</div>
form.component.ts
var id = this.route.snapshot.params['param'];
if (id != null) {
this.arService.get(param, true)
.subscribe(data => {
this.loading = false;
this.annualReturn = data;
this.attachments = this.annualReturn.attachments.filter(e => e.type == Enums.AttachmentType.Normal);
this.data = this.ensureData(data.formData);
this.annualReturn.formData = this.data;
this.dateConfig.disableUntil = { year: this.annualReturn.year - 1, month: 6, day: 30 };
this.dateConfig.disableSince = { year: this.annualReturn.year, month: 7, day: 1 };
// this.testprop = this.data.postalcontactperson;
this.stationInformationForm = formBuilder.group({
"survey.region": [this.data.survey.region],
"lesseeNames": [this.data.stationName, Validators.required],
// "somethingfancy": [this.data.postalcontactperson],
"postalcontactperson": [this.data.postalcontactperson],
"postalAddressGroup": formBuilder.group({
"postalcontactperson": [this.data.postalcontactperson, Validators.required],
"postalposition": [this.data.postalposition, Validators.required],
"postalemail": [this.data.postalemail, Validators.required],
"postalphone": [this.data.postalphone, Validators.required],
}, ),
You are referring to the incorrect formControlName in the template file. It's postalcontactperson not PostalContactPerson . Observe the Capitals P...C...P.... And better not to use [(ngModel)] as you already using Reactive Forms. FYI, refer below changes
Working stackblitz
Typescript file
export class AppComponent implements OnInit {
addressForm: FormGroup;
stationInformationForm: FormGroup;
data: any = {
acn: 1,
icn: 2,
postaladdress: {
contactperson: "Michael",
address: "Some Address"
}
};
constructor(private formBuilder: FormBuilder) {}
public ngOnInit() {
this.stationInformationForm = this.formBuilder.group({
businessNumbersGroup: this.formBuilder.group({
acn: [this.data.acn, Validators.required],
icn: [this.data.icn, Validators.required],
postalcontactperson: [this.data.postaladdress.contactperson, Validators.required]
})
});
// Getting inner form group
this.addressForm = this.stationInformationForm.get(
"businessNumbersGroup"
) as FormGroup;
// Getting Form Changes instead of using `[(ngModel)]`
this.addressForm.valueChanges.subscribe(data => console.log(data));
}
}
Template file
<div [formGroup]="addressForm">
<label>ACN</label>
<div class="form-description">Specify if applicable</div>
<input type="text" [ngClass]="{'has-error': !addressForm.valid && addressForm.get('acn').touched }" formControlName="acn" class="form-control" />
<hr />
<label>postalcontactperson</label>
<div class="form-description">Specify if applicable</div>
<input type="text" [ngClass]="{'has-error': !addressForm.valid && addressForm.get('postalcontactperson').touched }" formControlName="postalcontactperson" class="form-control" />
</div>
I am trying to create a simple 'it should create' unit test for one of my Angular components (the test generated by Angular CLI when generating the component). However, when running the test, I receive a TypeError: Cannot read property 'middle_name' of undefined. I didn't expect this error because the HTML is surrounded in an *ngIf.
I tried to follow this question on stackoverflow: Angular testing Cannot read property 'name' of undefined
However the OP resolved the problem by surrounding his HTML in an *ngIf, which is what my code currently does. I suspect the problem is occurring because this is a child component and is conditionally rendered.
form-submit-individual-success-component.ts:
it('should create', () => {
expect(component).toBeTruthy();
});
add-entity.ts:
onIndividualSubmit(clonedIndividualValues: Individual): void {
this.entityService.addIndividual(clonedIndividualValues)
.subscribe(individual => {
this.formIsSubmitted = true;
this.individualFormIsSubmitted = true;
this.individualId = individual.id;
this.individualFormData = individual;
})
}
add-entity.html:
<app-add-individual-form *ngIf="selectedOption == 'Individual' && !individualFormIsSubmitted" (individualServiceEmitter)="onIndividualSubmit($event)" [individualId]="individualId"></app-add-individual-form>
add-individual-form.ts:
#Output() individualServiceEmitter = new EventEmitter();
onIndividualSubmit(value: any): void {
value.eod_screening === 'Yes' ? value.eod_screnning = 1 : value.eod_screening = 0;
const clonedIndividualValues = Object.assign({ type: 'Individual', screening_status: 'Awaiting Submission' }, value)
this.individualServiceEmitter.emit(clonedIndividualValues);
}
add-individual-form.html:
<div class="form-group">
<label for="middle_name">Middle Name(s)</label>
<input type="text" class="form-control" id="middle_name" name="middle_name" formControlName="middle_name"
#middle_name>
<div *ngFor="let validation of validation_messages.middle_name">
<div *ngIf="individualForm.middle_name.hasError(validation.type) && (individualForm.middle_name.dirty || individualForm.middle_name.touched)"
class="alert alert-danger">
{{validation.message}}
</div>
</div>
</div>
<div class="form-group">
<label for="last_name">Last Name</label>
<input type="text" class="form-control" id="last_name" name="last_name" formControlName="last_name" #last_name
required>
<div *ngFor="let validation of validation_messages.last_name">
<div *ngIf="individualForm.last_name.hasError(validation.type) && (individualForm.last_name.dirty || individualForm.last_name.touched)"
class="alert alert-danger">
{{validation.message}}
</div>
</div>
</div>
<button type="submit" class="btn btn-success" [disabled]="!addIndividualForm.valid">Submit</button>
form-submit-individual-success.ts:
#Input() formData: Individual;
public individualFormData: Individual;
#Input() id: number;
public individualId: number;
public editIndividualBase = "/entity/edit";
constructor() { }
ngOnInit() {
this.individualFormData = this.formData;
}
form-submit-individual-success.html:
<p>First name: <span>{{individualFormData.first_name}}</span></p>
<p *ngIf="individualFormData.middle_name">Middle name(s): <span>{{individualFormData.middle_name}}</span></p>
<p>Last name: <span>{{individualFormData.last_name}}</span></p>
As described in the problem summary, I expect the component toBeTruthy (i.e. create successfully).
I have a normal input fields like this:
When i click on that "+" button this action happens and the service class is called as I have simple Json data arriving.I want to assign the selectionCustomOffice.custOfficeName=json data's.custOffcName; but I am getting the undefined result.
addedO(selectionCustomOffice:SelectionCustomOffice){
this.scoe=true;
this.selectionCustomOfficeService.getSingleCustomOffice(selectionCustomOffice.customOfficeId).subscribe((data)=>{
console.log("entered");
selectionCustomOffice.custOfficeName=data.custOffcName;
console.log( selectionCustomOffice.custOfficeName);
},(error)=>{
console.log(error);
});
this.empList.push(selectionCustomOffice);
this.selectionCustomOffice=new SelectionCustomOffice();
console.log(this.empList);
}
this.selectionCustomOfficeService.getSingleCustomOffice(selectionCustomOffice.customOfficeId).subscribe((data)=>{
console.log("entered");
selectionCustomOffice.custOfficeName=data.custOffcName;
console.log( selectionCustomOffice.custOfficeName);
},(error)=>{
console.log(error);
});
SelectionCustomOffice.ts
export class SelectionCustomOffice {
id: number;
fromDate: string;
toDate: string;
consignmentNo: number;
selectionId: number;
customOfficeId: number;
custOfficeName: string;
}
The form to send data is: I have used this field custom office as select field.
<div class="form-group row">
<div class="col-md-4">
<label>Custom Office</label>
</div>
<div class="col-md-2">
<label>From Date</label>
</div>
<div class="col-md-2">
<label>To Date</label>
</div>
<div class="col-md-4">Consignment No</div>
<div class="col-md-4">
<select class="form-control" id="customOfficeId" required [(ngModel)]="selectionCustomOffice.customOfficeId" name="customOfficeId"
>
<option *ngFor="let title of customoffices" [value]="title.custOfficeId">{{title.custOffcName}}</option>
</select>
</div>
<div class="col-md-2">
<input type="date" class="form-control" id="fromDate" required [(ngModel)]="selectionCustomOffice.fromDate" name="fromDate" />
</div>
<div class="col-md-2">
<input type="date" class="form-control" id="toDate" required [(ngModel)]="selectionCustomOffice.toDate" name="toDate" />
</div>
<div class="col-md-3">
<input type="number" class="form-control" id="consignmentNo" required [(ngModel)]="selectionCustomOffice.consignmentNo" name="consignmentNo">
</div>
<div class="col-md-1">
<button type="button" (click)="addedO(selectionCustomOffice)">+</button>
</div>
</div>
service class
getSingleCustomOffice(id: number): Observable<any> {
return this.http.get(`${this.baseUrl}/${id}`, { responseType: 'text' });
}
I think you have a small problem - You are reading your response as text
getSingleCustomOffice(id: number): Observable<any> {
return this.http.get(`${this.baseUrl}/${id}`, { responseType: 'text' });
}
Remove the { responseType: 'text' } from the http call or use JSON.parse(data) when you are reading data - { responseType: 'text' } this will return your response as string
Try like this if you want your response as text
this.selectionCustomOfficeService.getSingleCustomOffice(selectionCustomOffice.customOfficeId).subscribe((data)=>{
console.log("entered");
let outPut = JSON.parse(data);
selectionCustomOffice.custOfficeName=outPut.custOffcName;
console.log( selectionCustomOffice.custOfficeName);
},(error)=>{
console.log(error);
});
I think this might solve your problem - Happy coding !!
I've been battling with these block of codes for some days, and even when i try initializing it as an object i get errors.
this is my restaurantForm.ts file
import { Component, OnInit } from '#angular/core';
import {RestaurantService} from '../../restaurant.service';
import {ProductService} from '../../product.service';
import {ActivatedRoute, Router} from '#angular/router';
import 'rxjs/add/operator/take';
import {Product} from '../../model/product';
#Component({
selector: 'app-product-form',
templateUrl: './restaurant-form.component.html',
styleUrls: ['./restaurant-form.component.css']
})
export class RestaurantFormComponent implements OnInit {
restaurants$;
id;
product: Product;
constructor(private restaurantService: RestaurantService,
private productService: ProductService,
private route: ActivatedRoute,
private router: Router) {
this.restaurants$ = this.restaurantService.getAll();
this.id = this.route.snapshot.paramMap.get('id');
if (this.id) {
this.productService.get(this.id).take(1).subscribe(p => this.product = p);
}
this.product = new Product();
}
save(product) {
if (this.id) {
this.productService.update(this.id, product);
} else {
this.productService.create(product);
}
this.router.navigate(['/admin/restaurants']);
}
delete() {
if (!confirm('Are you sure you want to delete this product?')) { return ; }
this.productService.delete(this.id);
this.router.navigate(['/admin/restaurants']);
}
ngOnInit() {
}
}
this is my product model
export interface Product {
$key: string;
title: string;
price: number;
restaurant: string;
imageUrl: string;
}
My restaurantForm.html
<div class="container">
<div class="row">
<div class="col-md-6">
<form #f="ngForm" (ngSubmit)="save(f)">
<div class="form-group">
<label for="title">Title</label>
<input #title="ngModel" [(ngModel)]="product.title" name="title" id="title" type="text" class="form-control" required>
<div class="alert-danger alert" *ngIf="title.touched && title.invalid">
Title is required.
</div>
</div>
<div class="form-group">
<label for="price">Delivery Price</label>
<div class="input-group">
<span class="input-group-addon">₦</span>
<input #price="ngModel" [(ngModel)]="product.price" name="price" id="price"
type="number" class="form-control" required [min]="0">
</div>
<div class="alert alert-danger" *ngIf="price.touched && price.invalid">
<div *ngIf="price.errors.required">
Delivery Price is required
</div>
<div *ngIf="price.errors.min">
Delivery Price should be 0 or higher.
</div>
</div>
</div>
<div class="form-group">
<label for="restaurant">Restaurant</label>
<select #restaurant="ngModel" [(ngModel)]="product.restaurant" name="restaurant" id="restaurant" class="form-control" required>
<option value=""></option>
<option *ngFor="let r of restaurants$ | async" [value]="r.$key">
{{ r.name }}
</option>
</select>
<div class="alert alert-danger" *ngIf="restaurant.touched && restaurant.invalid">
Please select a restaurant.
</div>
</div>
<div class="form-group">
<label for="imageUrl">Image Url</label>
<input #imageUrl="ngModel" [(ngModel)]="product.imageUrl" name="imageUrl"
id="imageUrl" type="text" class="form-control" required url>
<div class="alert alert-danger" *ngIf="imageUrl.touched && imageUrl.invalid">
<div *ngIf="imageUrl.errors.required">Image Url is required.</div>
<div *ngIf="imageUrl.errors.url">Please enter a valid Url.</div>
</div>
</div>
<button class="btn btn-primary">Save</button>
<button type="button" (click)="delete()" class="btn btn-danger">Delete</button>
</form>
</div>
<div class="col-md-6">
<app-product-card [product]="product" [showActions]="false"></app-product-card>
</div>
</div>
</div>
I get the same errors with price, $key, restaurant and imageUrl.
thanks in advance. Although Ive looked up some solutions saying i should use elvis Operator e.g 'product?.title' this method isnt still working.
Because product is undefined, you need to declare and initialize it with empty object inside the constructor or ngOninit.
EDIT:
You need to have the Product declared in the component as,
const product : Produce = { $key: "", title: "",price:0,restuarant :"" ,imageurl:"" };
When the template get initialized, the product is undefined and it continues until the response return from API. Add a check for the template where you bind the object properties.Do the same for price etc.
<input *ngIf="product.title" #title="ngModel" [(ngModel)]="product.title" name="title" id="title" type="text" class="form-control" required>
I'm trying to add textfield dynamically with angular 2 and it works as expected,but couldn't managed to get this json object :
exemple of json object which i want to get when i clic the submit button :
{fullname:"toto",etapes:[{etape:"sometext"},{etape:"sometext"}]}
heres the HTML CODE:
<form [formGroup]="myForm" novalidate (ngSubmit)="save(myForm)">
<div style="padding:15px" class="container" style="width: 1027px !important;">
<div class="itineraire">
<div class="panel panel-default" style="width:100%">
<div class="panel-heading panelcolor"><span style="font-size: 15px;font-weight: bold">Itinéraire</span></div>
<div class="panel-body panelcolor">
<input type="text" formControlName="fullname" class="form-control" placeholder="fullename"
name="Location" >
<div formArrayName="myArray">
<div *ngFor="let myGroup of myForm.controls.myArray.controls; let i=index">
<div [formGroupName]="i">
<span *ngIf="myForm.controls.myArray.controls.length > 1" (click)="removeDataKey(i)" class="glyphicon glyphicon-remove pull-right"
style="z-index:33;cursor: pointer">
</span>
<!--[formGroupName]="myGroupName[i]"-->
<div [formGroupName]="myGroupName[i]">
<div class="inner-addon left-addon ">
<i class="glyphicon marker" style="border: 5px solid #FED141"></i>
<input type="text" style="width:50% !important" formControlName="etape" class="form-control" placeholder="Exemple : Maarif, Grand Casablanca"
name="Location" (setAddress)="getAddressOnChange($event,LocationCtrl)"><br/>
</div>
</div>
<!--[formGroupName]="myGroupName[i]"-->
</div>
<!--[formGroupName]="i" -->
</div>
</div>
<br/>
<a (click)="addArray()" style="cursor: pointer">+ Ajouter une ville étape</a>
<input type="text" style="width:30%" #newName id="newName" [hidden]="true">
</div>
</div>
<button type="submit" (click)="save()">save</button>
</form>
Component.ts :
initArray(nameObj:any) {
return this._fb.group({
[nameObj]: this._fb.group({
etape: [''],
gmtDate:[''],
})
});
}
addArray(newName:string) {
const control = <FormArray>this.myForm.controls['myArray'];
this.myGroupName.push(newName);
control.push(this.initArray(newName));
}
ngOnInit() {
this.myForm = this._fb.group({
myArray: this._fb.array([
this._fb.group({
test: this._fb.group({
etape: [''],
gmtDate:['']
})
}),
])
});
}
save(){
console.log(myObject);
}
so, what are the changes that i have to do in my code to get the like the Json object above, when i click the submit button, please help i got stuck on this.
If you want:
{fullname:"toto",etapes:[{etape:"sometext"},{etape:"sometext"}]}
your form should looks like: (we dont need the formGroupName )
this.myForm = this._fb.group({
fullname: ['', Validators.required ],
etapes: this._fb.array([
this._fb.group({
etape: ['']
},
this._fb.group({
etape: ['']
},
...
)
])
});
So, to have it dynamically, your initArray()should be like:
initArray() {
return this._fb.group({
etape: ['']
});
}
and adding an array should looks like:
addArray(newName:string) {
const control = <FormArray>this.myForm.controls['etapes']
control.push(this.initArray());
}
NB: You dont need the (click)="save()" anymore in the submit button, since you already call it when submit.
a working plunker: http://plnkr.co/edit/Nq4jrC5g0tfxE0NCTfoQ?p=preview
HI can you try like this
save(){
console.log(this.myForm.value);
}
#imsi imsi
you have
<div [formGroupName]="myGroupName[i]"> //WRONG
<div [formGroupName]="myGroup[i]"> //<--it's myGroup