Creating an add button for dynamic fields not working - javascript

I am trying to create a dynamic field with an add button and a delete button with the Address class. I am stuck as to why the addAddress function does not work. I searched around for a solution but nothing I have searched has worked. I am a novice with Angular so I might be making this more complicated then it needs to be. Here is the app.component.ts
import { FormGroup, FormControl, FormArray, FormBuilder } from
'#angular/forms';
import { Component, OnInit } from '#angular/core';
import { Validators} from '#angular/forms';
class Address{
constructor(public stName, public aptNo, public pinCode){
}
}
class registrationModel{
constructor(public firstName, public lastName,public age,public fromStates,
public state, public homeAddress:Array<Address> ){}
}
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
private _formObject:FormGroup;
private _formModel:registrationModel;
private _addressObject:Address;
private _createFormGroup(){
this._formObject = this._formBuilder.group({
addLabelTitle:["", Validators.minLength(2)],
addLabelType:["", Validators.minLength(2)],
firstName:[],
lastName:[],
age:[18, [Validators.min(18), Validators.max(60)]],
fromStates:[false],
state:[],
stName: [],
aptNo: [],
pinCode: [],
homeAddress:this._formBuilder.array([Address])
});
this._formObject.reset(this._formModel);
console.info(this._formObject);
}
private _submitValue(){
// this._formObject = this._formBuilder.group({
// addLabelTitle:[],
// addLabelType:[],
// firstName:[],
// lastName:[],
// age:[],
// fromStates:[false],
// state:[]
// });
console.info(this._formObject.value);
}
private _resetValue(){
this._formObject.reset();
}
private _addAddress(){
this._addressObject = new Address("","","");
/*
Create a address model.
Inject it to formObject.
*/
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<small>{{this._formObject.value|json}}</small>
<!--The content below is only a placeholder and can be replaced.-->
<div class="registrationForm" [formGroup]="_formObject">
<!-- Name Input box -->
<div class="formGroup">
<label>Name :</label>
<input type="text" placeholder="First Name" formControlName="firstName"
ngModel required>
<input type="text" formControlName="lastName" placeholder="Last Name"
ngModel required>
</div>
<!-- Name Age box -->
<div class="formGroup">
<label>Age :</label>
<input type="number" placeholder="Age" formControlName="age">
<small *ngIf="_formObject.controls.age.errors">
{{getErrors(_formObject.controls.age.errors)}}</small>
</div>
<!-- form United States -->
<div class="formGroup">
<label>From United States </label>
<input type="checkbox" formControlName="fromStates" ngModel required>
</div>
<!-- States -->
<div class="formGroup">
<label>States :</label>
<select formControlName="state">
<option value="co">Colordo</option>
<option value="ca">California</option>
</select>
</div>
<div class="formGroup">
<label>formControlName </label>
<select formControlName="state">
<option value="co">Colordo</option>
<option value="ca">California</option>
</select>
</div>
<hr/>
<div formArrayName="homeAddress">
<button>Delete</button>
<div *ngFor="let address of this._formObject.controls.homeAddress.controls;
let i=index">
<div [formGroupName]="i">
<div class="formGroup">
<label>St Name :</label>
<input type="text" placeholder="" formControlName="stName" ngModel
required>
</div>
<div class="formGroup">
<label>Apt Number :</label>
<input type="text" placeholder="" formControlName="aptNo" ngModel
required>
</div>
<div class="formGroup">
<label>Pincode :</label>
<input type="text" placeholder="" formControlName="pinCode" ngModel
required>
</div>
<!-- <div class="formGroup">
<label>Add Label: </label>
<input type="text" placeholder="Label Title"
formControlName="addLabelTitle">
<input type="text" placeholder="Type (Text, Checkbox, etc)"
formControlName="addLabelType">
</div>
-->
</div>
<hr/>
</div>
<div class="formGroup text-center">
<button (click)="_addAddress()">Add address</button>
<!-- Submit -->
<button (click)="_submitValue()">Submit</button>
<!-- Cancel -->
<button (click)="_resetValue()">Cancel</button>
</div>
</div>

You need to add a formgroup to your form array, if you like to use the class Address you have, you can do it by
_addAddress() {
let formArr = this._formObject.controls.homeAddress;
formArr.push(this._formBuilder.group(new Address('','','')))
}
You can remove all ngModel and required from your form, these belong with template driven forms.
The build of the form is I would create an empty FormArray, and then just call _addAddress after the build of the form since you probably want an initial formgroup in your form array.
As a sidenote, I can't see that the following would even work (?)
homeAddress:this._formBuilder.array([Address])
So I would scrap that and do:
_createFormGroup(){
this._formObject = this._formBuilder.group({
// all other form controls here
homeAddress:this._formBuilder.array([])
});
this._addAddress();
}

Related

Prepopulate the existing values in the form field in Angular

I want to update existing data information using update data form. The input should populate the existing values. How to do that?
As of now, I have to enter all the fields manually to update the form.
Update doctor .ts file
import { Component, OnInit } from '#angular/core';
import { FormArray, FormBuilder, FormControl, FormGroup } from '#angular/forms';
import { ActivatedRoute, Router } from '#angular/router';
import { Doctor } from '../doctor';
import { DoctorService } from '../doctor.service';
#Component({
selector: 'app-update-doctor',
templateUrl: './update-doctor.component.html',
styleUrls: ['./update-doctor.component.css']
})
export class UpdateDoctorComponent implements OnInit {
id:any;
doctor:Doctor;
updateForm:FormGroup;
constructor(private route: ActivatedRoute, private router: Router,private doctorservice: DoctorService,private formbuilder:FormBuilder) {
}
ngOnInit() {
this.doctor = new Doctor();
}
updateDoctor(){
this.doctorservice.updateDoctor( this.doctor)
.subscribe(data =>{
console.log(data);
this.doctor = new Doctor();
window.location.reload();
})
this.gotoList();
}
onSubmit(){
this.updateDoctor();
}
gotoList() {
this.router.navigate(['doctor']);
}
}
update doctor .html file
<div class="card col-md-4 offset-md-4 mt-3" >
<h3>Update Doctor</h3>
<div style="width: 100% ;">
<form (ngSubmit)="onSubmit()">
<div class="form-group">
<label for="doctorId"> Id</label>
<input type="text" class="form-control" id="doctorId" required [(ngModel)]="doctor.doctorId" name="doctorId" #doctorId>
</div>
<div class="form-group">
<label for="doctorName"> Name</label>
<input type="text" class="form-control" id="doctorName" value="{{doctor.doctorName}}" required [(ngModel)]="doctor.doctorName" name="doctorName" #doctorId>
</div>
<div class="form-group">
<label for="doctorProfile">Profile</label>
<input type="text" class="form-control" id="doctorProfile" required [(ngModel)]="doctor.doctorProfile" name="doctorProfile">
</div>
<div class="form-group">
<label for="doctorSpeciality">Speciality</label>
<input type="text" class="form-control" id="doctorSpeciality" value="{{doctor.doctorSpeciality}}" required [(ngModel)]="doctor.doctorSpeciality" name="doctorSpeciality">
</div>
<div class="form-group">
<label for="doctorQualification">Qualification</label>
<input type="text" class="form-control" id="doctorQualification" value="{{doctor.doctorQualification}}" required [(ngModel)]="doctor.doctorQualification" name="doctorQualification">
</div>
<div class="form-group">
<label for="doctorEmail">Email</label>
<input type="text" class="form-control" id="doctorEmail" value="{{doctor.doctorEmail}}" required [(ngModel)]="doctor.doctorEmail" name="doctorEmail">
</div>
<div class="form-group">
<label for="doctorPassword">Password</label>
<input type="password" class="form-control" id="doctorPassword" required [(ngModel)]="doctor.doctorPassword" name="doctorPassword">
</div>
<button type="submit" class="btn btn-dark">Submit</button>
</form>
</div>
</div>
From this function I am navigating to update doctor form
updateDoctor(){
this.router.navigate(['update'])
}
service method for update.
updateDoctor(doctor:Object):Observable<Object>{
return this.http.put(`${this.baseUrl1}`,doctor);
}
You could write a service to get the existing form data and load the data in the form through this.doctor object on load.

ngModel is not binding select in angular 4

I have a form in my application which contains title, price, category (select) and imagUrl data. I applied ngModel with every field and it's working fine except the select element. When I console.log() form data I get the value of every field but the value of the select element which is undefined. I imported the AngularForms module in app.module.ts
this is my product-form-component-html code
<form #f="ngForm" (ngSubmit)="save(f.value)" >
<div class="form-group">
<label for="title">Title</label>
<input ngModel name="title" id="title" type="text" class="form-control">
</div>
<div class="form-group">
<label for="price">Price</label>
<div class="input-group">
<span class="input-group-addon">$</span>
<input ngModel name="price" id="price" type="number" class="form-control">
</div>
</div>
<div class="form-group">
<label for="category">category</label>
<select ngModel name="category" id="category" class="form-control">
<option value=""></option>
<option *ngFor="let c of categories$ | async" [value]="c.key$">
{{ c.name }}
</option>
</select>
</div>
<div class="form-group">
<label for="imageUrl">image URL</label>
<input ngModel name="iamgeUrl" id="imageUrl" type="text" class="form-control">
</div>
<button class="btn btn-primary">Save</button>
</form>
this is product-form-component.ts file
import { Component, OnInit } from '#angular/core';
import { CategoryService } from '../../category.service';
import { ProductService } from '../../product.service';
#Component({
selector: 'app-product-form',
templateUrl: './product-form.component.html',
styleUrls: ['./product-form.component.css']
})
export class ProductFormComponent implements OnInit {
categories$;
constructor(categoryService: CategoryService, private productService: ProductService ) {
this.categories$ = categoryService.getCategories();
}
ngOnInit() {
}
save(product) {
console.log(product);
this.productService.create(product);
}
}
this is product-service.ts
import { Injectable } from '#angular/core';
import { AngularFireDatabase } from 'angularfire2/database';
#Injectable()
export class ProductService {
constructor(private db: AngularFireDatabase) { }
create(product) {
return this.db.list('/products').push(product);
}
}
what am I doing wrong? please help me with detailed answer
my Firebase Database
this is the answer [value]="c.$key"
. I was assigning [value]="c.key$" that is why i was getting error.

How to hide a input field according to the value of selection in angular?

I have three input fields :
All three fields are shown when the page is loaded first but when I select the value1 then address field should be shown and phone number should be hidden. Similarly when value2 is clicked phone number is shown and address is hidden.
<div class="form-group col-md-3">
<label for="age">Address</label>
<input type="text"
id="address"
class="form-control"
name="address"
placeholder="Enter the address"
[(ngModel)]="selection.address"
#address="ngModel"
[ngClass]="{ 'is-invalid': f.submitted && selectionDate.invalid }"
required
/>
<div *ngIf="f.submitted && address.invalid" class="invalid-input">
<!-- individual validation errors -->
<div *ngIf="address.errors?.required">Address is required</div>
</div>
</div>
<div class="form-group col-md-3">
<label for="age">Phone Number</label>
<input type="text"
id="phoneNumber"
class="form-control"
name="phoneNumber"
placeholder="Enter the Phone number"
[(ngModel)]="selection.phoneNumber"
#phoneNumber="ngModel"
[ngClass]="{ 'is-invalid': f.submitted && phoneNumber.invalid }"
required />
<div *ngIf="f.submitted && phoneNumber.invalid" class="invalid-input">
<!-- individual validation errors -->
<div *ngIf="phoneNumber.errors?.required">Phone Number is required</div>
</div>
</div>
</div>
<!--row 3-->
<div class="col-md-12">
<div class="form-group col-md-3">
<label for="selectionType">Selection Type</label>
<select class="form-control" id="selectionType"
[(ngModel)]="selection.selectionType" name="selectionType" required #selectionType="ngModel" [ngClass]="{ 'is-invalid': f.submitted && selectionType.invalid }">
<option value="value1">Value1</option>
<option value="value2">Value2</option>
</select>
<div *ngIf="f.submitted && selectionType.invalid" class="invalid-input">
<!-- individual validation errors -->
<div *ngIf="selectionType.errors?.required">Selection Type is required</div>
</div>
</div>
In this above original code, I tried to make changes like:
<option value="value1" (click)="callme()">Value1</option>
This is within the selection.component.ts file. I also tried to print to the console and tried to output my logic but I am not seeing any changes.
callme(){
console.log("call me");
}
How can I achieve this? Is there a new method to do it?
Use change evet binding and boolena to track changes:
Refer:
https://stackblitz.com/edit/angular-qihhhh?file=src%2Fapp%2Fapp.component.html
app.component.html
<form action="javascript:;">
<div class="form-group" *ngIf="isNameSelected">
<label for="name">name :</label>
<input type="text" class="form-control" id="name">
</div>
<br>
<div class="form-group" *ngIf="!isNameSelected">
<label for="address">address:</label>
<input type="text" class="form-control" id="address">
</div>
<br/>
<select (change)="selectInput($event)">
<option value="Value-1">Value-1</option>
<option value="Value-2">Value-2</option>
</select>
</form>
app.component.ts
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
isNameSelected: boolean;
selectInput(event) {
let selected = event.target.value;
if (selected == "Value-1") {
this.isNameSelected = true;
} else {
this.isNameSelected = false;
}
}
}
You should add the event onto the select tag
<select (change)="callme($event)"></select>
then in your component you can create a method as follows
callme(event): void {
const selectedValue = event.target.value;
console.log(selectedValue);
}
You would also need to add a conditional *ngIf onto the outer div for both address and phone number to display the selected one
I have created an example here for you: https://stackblitz.com/edit/angular-rpxt4o?embed=1&file=src/app/app.component.ts
Component:
#ViewChild('address', {read: ElementRef}) address: ElementRef;
#ViewChild('phoneNumber', {read: ElementRef}) phoneno: ElementRef;
callme(event): void {
const selectedValue = event.target.value;
if(selectedValue === 'value1'){
this.address.nativeElement.style.display = 'none';
this.phoneno.nativeElement.style.display = 'block';
else if(selectedValue === 'value2'){
this.phoneno.nativeElement.style.display = 'none';
this.address.nativeElement.style.display = 'block';
}
}
Inside select tag use (change)="callme()", so as to be triggered on every change of the selected option.
<select #sel (change)="callme($event, sel.value)">
</select>
Hide/show each field using this template variable:
<input *ngIf="sel.value === 'value1'">
Modify your code to fit your exact needs.
In my case, I was required to hide multiple form fields depends upon multiple type, so what i did is,
Created class with all form fields
export class FormFields {
public jobTitle: boolean ;
public opportunityType: boolean ;
public industry: boolean ;
public jobType: boolean ;
public jobTags: boolean;
}
created function to hide the fields from object provided
changeFieldVisibilityOnType(formObject, listOfFields) {
for (let [key, value] of Object.entries(formObject)) {
formObject[key] = listOfFields.includes(key) ? false : true;
}
}
3.into the HTML form handled the change event.
<select class="form-control " name="Type" [(ngModel)]="model.Type"
(change)="onChange($event)">
<option data-display="Type">Select Type</option>
<option [value]="jType.key"
*ngFor="let jType of masters.Types">{{jType.value}}
</option>
And finally into onChange() function, passed the object and array of fields required to hide depends on value selected to the changeFieldVisibilityOnType funtion.
onChange(event) {
switch (event.target.value) {
case 'JOB':
var listOfFields = ["industry", "jobType"];
this.changeFieldVisibilityOnType(this.objFormFields, listOfFields);
break;
case 'PAID_INTERN':
listOfFields = ["jobType"];
this.changeFieldVisibilityOnType(this.objFormFields, listOfFields);
break;
}
}
Hope this will help someone. Best Luck!!

Angular 5 not showing user entered values from formarray

In angular 5 I am trying to add new row and remove row functionality. For add new row and delete row I have taken code from here. Everything is working fine but when I am trying to get the user entered value in the new row fields I am not getting those values.
I am getting the value for Event Name. But for other 3 fields like Package Name, Package Price, Max Purchase Limit, I am not getting them.
Here is the code what I have tried.
my event-create.component.html looks like this
<div class="container col-md-12">
<h1 class="page-header">Create Event</h1>
<div class="row show-hide-message">
<div [ngClass]= "messageClass">{{message}}</div>
</div>
<form [formGroup] = "form" (ngSubmit)="onEventSubmit()">
<fieldset>
<div class="form-group">
<label for="eventname">Event Name</label>
<div class='form-group' [ngClass]="{'has-error': form.controls.eventname.errors && form.controls.eventname.dirty,
'has-success': !form.controls.eventname.errors
}">
<input type="text" class="form-control" autocomplete="off" placeholder="Event Name" formControlName="eventname">
<ul class="help-block">
<li *ngIf="(form.controls.eventname.errors?.minlength ) && form.controls.eventname.dirty">Event name should be atleast 5 characters</li>
</ul>
</div>
</div>
<h4>Package Price</h4>
<hr>
<div class="row" formArrayName="sections">
<div class="col-md-12" *ngFor="let section of getSections(form); let i = index">
<div class="form-group col-md-5">
<label for="packagename">Package Name</label>
<input type="text" class="form-control" autocomplete="off" placeholder="Package Name" formControlName="packagename" >
</div>
<div class="form-group col-md-2">
<label for="packageprice">Package Price</label>
<input type="number" class="form-control" autocomplete="off" placeholder="Package Price" formControlName="packageprice" >
</div>
<div class="form-group col-md-2">
<label for="packagelimit">Max Purchase Limit</label>
<input type="number" class="form-control" formControlName="packagelimit" autocomplete="off" >
</div>
<div class="form-group col-md-1">
<br/>
<input type="button" (click)="addPackageRow()" class="btn btn-md btn-success" value="+" name="">
</div>
<div class="form-group col-md-1" *ngIf="getSections(form).length > 1">
<br/>
<input type="button" (click)="removeSection(i)" class="btn btn-md btn-error" value="-" name="">
</div>
</div>
</div>
<input [disabled]=!form.valid type="submit" class="btn btn-primary" value="Submit">
<pre>{{form.value | json}}</pre>
</fieldset>
</form>
</div>
and my event-create.component.ts looks like this
import { Component, OnInit } from '#angular/core';
import { FormArray, FormBuilder, FormControl, FormGroup, Validators } from '#angular/forms';
import { FormControlName } from '#angular/forms/src/directives/reactive_directives/form_control_name';
#Component({
selector: 'app-event-create',
templateUrl: './event-create.component.html',
styleUrls: ['./event-create.component.css']
})
export class EventCreateComponent implements OnInit {
form : FormGroup;
packagesArray: FormArray;
constructor(
private formBuilder : FormBuilder,
) { this.createEventForm() }
createEventForm() {
this.form = this.formBuilder.group({
eventname: ['', Validators.compose([
Validators.required,
Validators.minLength(5)
])],
packages: this.packagesArray
})
}
ngOnInit() {
this.form = new FormGroup({
eventname: new FormControl(''),
sections: new FormArray([
this.initSection(),
]),
});
}
initSection() {
return new FormGroup({
packagename: new FormControl(''),
packageprice: new FormControl(''),
packagelimit: new FormControl('')
});
}
initItemRows() {
return this.formBuilder.group({
itemname: ['']
});
}
onEventSubmit() {}
public addPackageRow() {
const control = <FormArray>this.form.get('sections');
control.push(this.initSection());
}
initOptions() {
return new FormGroup({
optionTitle: new FormControl('')
});
}
addSection() {
const control = <FormArray>this.form.get('sections');
control.push(this.initSection());
}
getSections(form) {
return form.controls.sections.controls;
}
public removeSection(i){
const control = <FormArray>this.form.get('sections');
control.removeAt(i);
}
}
Its not showing user entered value in html page also not doing any validation for the eventname field.
Here is the demo what I have done so far
https://stackblitz.com/edit/angular-3s5wwf
Can someone tell me what is going wrong here. Any suggestion or advice will be really appreciable. Thanks.
You need to add this in line 23 and 24
<div class="row" formArrayName="sections">
<div class="col-md-12" *ngFor="let section of getSections(form); let i = index" [formGroupName]="i">
you missed adding the formGroupName for the formArrayName
workinglink

When using template driven forms in Angular 2, how to access the form in the component?

I have a simple template driven form like so:
HTML:
<div class="container">
<h1>Hero Form</h1>
<form (ngSubmit)="onSubmit()" #heroForm="ngForm">
<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control" id="name" [(ngModel)]="model.name" name="name" #name="ngModel">
</div>
<div class="form-group">
<label for="alterEgo">Alter Ego</label>
<input type="text" class="form-control" id="alterEgo" [(ngModel)]="model.alterEgo" name="alterEgo">
</div>
<div class="form-group">
<label for="power">Hero Power</label>
<select class="form-control" id="power" [(ngModel)]="model.power" name="power">
<option *ngFor="let pow of powers" [value]="pow">{{pow}}</option>
</select>
</div>
<button type="submit" class="btn btn-success" [disabled]="!heroForm.form.valid">Submit</button>
</form>
</div>
Component:
import { Component, OnInit } from '#angular/core';
import { Hero } from './hero';
#Component({
selector: 'at-hero',
templateUrl: './hero.component.html',
styleUrls: ['./hero.component.scss']
})
export class HeroComponent implements OnInit {
constructor() {
//
}
ngOnInit() {
//
}
powers = ['Really Smart', 'Super Flexible', 'Super Hot', 'Weather Changer'];
model = new Hero(18, 'Dr IQ', this.powers[0], 'Chuck Overstreet');
submitted = false;
onSubmit() { this.submitted = true; }
newHero() {
this.model = new Hero(42, '', '');
}
}
How can I:
Reset the whole form from the component (not from the markup)?
Reset a single form field (e.g. the name field) also from the component and not the markup?
You can get the form by using ViewChild
Markup
<form (ngSubmit)="onSubmit()" #heroForm="ngForm">
...
</form>
Component
#ViewChild('heroForm') public heroForm: NgForm;
I suggest you also to look at Reactive Forms too. I think this will be more handy if you want to work with form in the typescript, not in the markup

Categories

Resources