How do you add elements and access values dynamically in Angular? - javascript

I am working on a small project that allows the user to add dynamic fields. On clicking a button I have been able to create input fields dynamically. I am trying to access the value of each field and push it to the service. On the other hand, another component should make the number of div depending upon the number of input fields created by the user and each div should contain a title depending upon the user input in the input field.
register.component.html
<h2>Demo App</h2>
<form [formGroup]="myForm">
<button (click)="addRooms()">Add Room </button>
<div formArrayName="addRoom">
<div *ngFor="let r of Rooms.controls; let i=index" [formGroupName]="i">
<mat-form-field>
<input matInput placeholder="Enter A Room Name" formControlName="roomName" (keyup)="abc()"/>
</mat-form-field>
<button (click)="deleteRoom(i)">Delete</button>
</div>
</div>
<input type="button" (click)="getRoomValues()" value="Get">
</form>
register.component.ts
import { Component, OnInit} from '#angular/core';
import { RegisterModel } from '../models/register.model';
import {FormGroup, FormBuilder, Validators, FormArray, FormControl } from '#angular/forms';
import { Router } from '#angular/router';
#Component({
selector: 'app-register',
templateUrl: './register.component.html',
styleUrls: ['./register.component.css']
})
export class RegisterComponent implements OnInit, AfterViewInit {
myForm: FormGroup;
room: FormGroup;
constructor(private formBuilder:FormBuilder, private r:Router, private _ele:ElementRef, private _render: Renderer) { }
ngOnInit() {
this.myForm = this.formBuilder.group({
addRoom: this.formBuilder.array([]),
tst: new FormControl()
});
}
getVal(){
console.log(this.myForm.value.tst);
}
get Rooms(){
return this.myForm.get('addRoom') as FormArray;
}
addRooms(){
this.room = this.formBuilder.group({
roomName:new FormControl()
})
this.Rooms.push(this.room);
console.log(this.Rooms);
}
abc(){
console.log(this.room.value.roomName);
}
deleteRoom(i){
this.Rooms.removeAt(i);
}
get roomNames(){
return this.myForm.get('roomNames') as FormArray;
}
getRoomValues(){
console.log(this.myForm.value.addRoom)
}

Below is the code sample for couple of fields with dynamic Add & Remove functionality.
<form [formGroup]="linksForm" class="form-horizontal">
<div class="form-group">
<label class="col-md-2 control-label">Links
</label>
<div class="col-md-10">
<div formArrayName="links" *ngFor="let item of linksForm.get('links').controls; let i = index;">
<div [formGroupName]="i">
<div class="col-md-5">
<input class="form-control col-md-5" formControlName="name" placeholder="Name">
</div>
<div class="col-md-5">
<input type="url" pattern="https?://.+" placeholder="http://example.com" class="form-control col-md-5"
formControlName="link">
</div>
<div class="col-md-2">
<button class="btn btn-warning btn-xs m-t-sm" type="button" (click)="removeItem(i)">
<i name="save" class="fa fa-trash"></i>
</button>
<button *ngIf="i == linksForm.get('links').controls.length - 1" class="btn btn-primary btn-xs m-t-sm" type="button" (click)="addItem()">
<i name="save" class="fa fa-plus"></i>
</button>
</div>
</div>
</div>
</div>
</div>
</form>
TS : Declare below variables in class :
linksForm: FormGroup;
links: FormArray;
Inside ngOnInit() initialize form with at least one row :
this.linksForm = new FormGroup({
'links': new FormArray([this.createItem()])
});
Add below functions for Add / Remove :
addItem(): void {
this.links = this.linksForm.get('links') as FormArray;
this.links.push(this.createItem());
}
removeItem(index: any) {
this.links.removeAt(index);
if (this.links.length == 0) {
this.addItem();
}
}
createItem(): FormGroup {
return new FormGroup({
id: new FormControl(),
name: new FormControl(),
link: new FormControl(),
createdAt: new FormControl()
});
}

Related

How would I go about binding form input from multiple child components to an array defined in a parent component?

I am trying to bind form input from multiple child components (item-input-component) to array itemList[] defined in a parent component (add-invoice-component). I want to take three inputs (itemName, quantity, price), create an Item object out of them, then output that Item object from item-input-component and add it to itemList[]. How can I do that ? Is that even possible ? And if not, what's a good solution ?
add-invoice-component.html
<form>
<div>
<h2>Items</h2>
<app-item-input *ngFor="let item of numArray"></app-item-input>
<button (click)="incrementNumOfItems()">Add Item</button>
</div>
</form>
add-invoice-component.ts
import { Component, ElementRef, OnInit, Renderer2 } from '#angular/core';
import { Item } from 'src/app/models/item';
#Component({
selector: 'app-add-invoice',
templateUrl: './add-invoice.component.html',
styleUrls: ['./add-invoice.component.css']
})
export class AddInvoiceComponent implements OnInit {
description!: string;
invoiceDate!: Date;
clientName!: string;
clientAddress!: string;
itemList!: Item[];
numOfItems: number = 2;
numArray: number[] = Array(2).fill(0).map((x,i)=>i);
constructor( private el: ElementRef) { }
ngOnInit(): void {
}
incrementNumOfItems() {
this.numOfItems++;
this.numArray = Array(this.numOfItems).fill(0).map((x,i)=>i);
}
removeItem() {
this.el.nativeElement.remove()
}
}
item-input-component.html
<div class="mb-3 row item">
<div class="col">
<label for="item-name" class="form-label">Item Name</label>
<input type="text" id="item-name" name="clientName" class="form-control">
</div>
<div class="col">
<label for="quantity" class="form-label">Quantity</label>
<input type="text" id="quantity" name="quantity" class="form-control">
</div>
<div class="col">
<label for="price" class="form-label">Price</label>
<input type="text" id="price" name="price" class="form-control">
</div>
<button (click)="removeItem()">Delete Item</button>
item-input-component.ts
import { Component, ElementRef, OnInit , Renderer2} from '#angular/core';
#Component({
selector: 'app-item-input',
templateUrl: './item-input.component.html',
styleUrls: ['./item-input.component.css']
})
export class ItemInputComponent implements OnInit {
itemName!: string;
quantity!: number;
price!: number;
constructor(private el: ElementRef) { }
ngOnInit(): void {
}
removeItem() {
this.el.nativeElement.remove()
}
}
Item.ts
export interface Item {
itemName: string,
quantity: number,
price: number
}
The question is about pass to your child component an object, to Delete you need use Output to comunicate with the parent
This object will be an object with properties: itemName, quantity and price -and the you use [(ngModel)] or a FormGroup -and you use ReactiveForms-
#Input()element:any
#Output() deleteItem:EventEmitter<any>:new EventEmitter<any>()
<input ... [(ngModel)]="element.clientName">
<input ... [(ngModel)]="element.quantity">
<input ... [(ngModel)]="element.price">
<button (click)="deleteItem.emit(null)">Delete Item</button>
Your parent
<app-item-input *ngFor="let item of list;let i=index"
[element]="list[i]"
(deleteItem)="removeItem(i)"
></app-item-input>
where
list:any[]=this.numArray.map(_=>({
clientName:'',
quantity:0,
price:0
}))
//see that removeItem remove one value of the array.
//**NOT** about your .html
removeItem(index:number) {
this.list.splice(index,1)
}
Using a FormArray is looks like
formGroup:FormGroup;
#Input('group') set _group(value)
{
this.formGroup=value as FormGroup
}
#Output() deleteItem:EventEmitter<any>:new EventEmitter<any>()
<form [formGroup]="fromGroup">
<input ... formControlName="clientName">
<input ... formControlName="quantity">
<input ... formControlName="price">
</form>
<button (click)="deleteItem.emit(null)">Delete Item</button>
And the parent
<app-item-input *ngFor="let item of listFormArray.controls;let i=index"
[group]="listFormArray.at(i)"
(deleteItem)="removeItem(i)"
></app-item-input>
listFormArray:FormArray[]=new FormArray(
this.numArray.map(_=>(new FormGroup({
clientName:new FormControl(null),
quantity:new FormControl(0),
price::new FormControl(0)
})))
)
removeItem(index:number) {
this.formArray.removeAt(index)
}
Looks like you're not familiar with Angular services, so here's an example to show you how it works.
Stackblitz: https://stackblitz.com/edit/angular-ivy-afppeb?file=src/app/item.service.ts
Here's a simple service to hold the items, it has add and delete methods
Item Service
#Injectable({ providedIn: 'root' })
export class ItemService {
itemList: Item[] = [];
addItem(item: Item) {
this.itemList.push(item);
}
deleteItem(index: number) {
this.itemList.splice(index, 1);
}
}
To access this service you just inject it via the constructor of any component:
Add Invoice Component
export class AddInvoiceComponent {
constructor(private itemService: ItemService) {}
get items() {
return this.itemService.itemList;
}
delete(index: number) {
this.itemService.deleteItem(index);
}
}
<app-item-input></app-item-input>
<h1>Items</h1>
<ng-container *ngFor="let item of items; index as i">
<pre>{{ item | json }}</pre>
<button (click)="delete(i)">Delete</button>
</ng-container>
And here's a simple way to convert the form data to an object
Item Input Component
export class ItemInputComponent {
formGroup = new FormGroup({
itemName: new FormControl(''),
quantity: new FormControl(0),
price: new FormControl(0),
});
constructor(private itemService: ItemService) {}
onSubmit() {
this.itemService.addItem(this.formGroup.getRawValue());
}
}
<h1>Input</h1>
<form [formGroup]="formGroup" (ngSubmit)="onSubmit()">
<div>
<label>Item Name:</label>
<input type="text" formControlName="itemName" />
</div>
<div>
<label>Quantity:</label>
<input type="number" formControlName="quantity" />
</div>
<div>
<label>Price:</label>
<input type="number" formControlName="price" />
</div>
<button type="submit">Submit</button>
</form>
You may want to do form validation as well, but this is just to show you how the service works.

Angular 7 dynamic form validation using reactive forms

I am currently developing a dynamic form builder it has an admin side and a user side, on the admin side you can set the name of the input and type eg: first name and textbox you can add or take away from fields and there are a set amount of types you can choose from, when you are done the admin will then save the form to the Database. On the user frontend the from is pulled from the Database and using patchValue the from is set the problem I am having is with the user's input to the questions on the form. I am trying to figure out how I can first set the type and placeholder of the input that the user uses to answer the questions.
As well as dynamically apply validation rules to each input, so, for instance, a user wants to fill out a form with their first name, last name, age, and CV for the first and last name I want to have required and a regex expression to only allow certain characters, for the age I want to have a min and max number and cv required. and when the user submits the form I only want to send the name and value of an input and not the whole form.
But keep in mind that these forms are completely dynamic so I need to validate the user's input based on the input type that is set
/*Typescript Code*/
import { Component, OnInit } from '#angular/core';
import { FormArray, FormBuilder, FormGroup, Validators } from '#angular/forms';
import { FormService} from '../form.service';
import { ActivatedRoute } from '#angular/router';
#Component({
selector: 'app-reactive',
templateUrl: './reactive.component.html',
styleUrls: ['./reactive.component.scss']
})
export class ReactiveComponent implements OnInit {
public form: FormGroup;
public fieldList: any;
types: Array<any>;
formData: any;
Param: string;
get contactFormGroup() {
return this.form.get('inputs') as FormArray;
}
constructor(
private route: ActivatedRoute,
private fb: FormBuilder,
private api: FormService) { }
ngOnInit() {
/*First I initlize the form*/
this.form = this.fb.group({
name: [null, Validators.compose([Validators.required])],
organization: [null, Validators.compose([Validators.required])],
inputs: this.fb.array([this.createForm()])
});
this.route.paramMap.subscribe(params => {
this.Param = params.get('id');
this.getForm(this.Param);
});
// set fieldslist to this field
this.fieldList = this.form.get('inputs') as FormArray;
}
// formgroup
/*The I initilize the form array of inputs*/
createForm(): FormGroup {
return this.fb.group({
type: [null, Validators.compose([Validators.required])],/*These come from the DB*/
name: [null, Validators.compose([Validators.required])],/*These come from the DB*/
value: [null, Validators.compose([Validators.required])] /*This gets filled in by the user*/
});
}
/*The I use my API service to call the DB using the form Id*/
getForm(id) {
this.api.getForm(id).subscribe(
(data: any) => this.setForm(data)
);
}
getFieldsFormGroup(index): FormGroup {
const formGroup = this.fieldList.controls[index] as FormGroup;
return formGroup;
}
/*Here I set my form data*/
setForm(data) {
const d = data.results;
this.form.patchValue({
name: [d[0].form_name],
organization: [d[0].org],
});
this.form.setControl('inputs', this.setExistingFields(d[0].fields));
}
/*Here I set my inputs array data*/
setExistingFields(fields: any): FormArray {
const formArray = new FormArray([]);
this.fieldList = formArray;
fields.forEach(f => {
formArray.push(this.fb.group({
name: f.name,
type: f.type,
value: f.value
}));
});
return formArray;
}
submit() {
/* Here when I send my form back to the server I only want to send the inputs name and value nothing else */
console.log(this.form.value.inputs);
}
}
/*HTML CODE*/
<div class="container p-1">
<div class="row">
<div class="col-12">
<form class="md-form" [formGroup]="form" #submittion (submit)="submit()">
<div class="card">
<div class="card-header">Form Name</div>
<div class="card-body">
<div class="row">
<div class="form-group col-6">
<i class="fab fa-wpforms prefix"></i>
<input class="form-control" placeholder="Form Name" formControlName="name" type="text" readonly>
</div>
<div class="form-group col-6">
<i class="far fa-building prefix"></i>
<input class="form-control" placeholder="Organization" formControlName="organization" type="text"
readonly>
</div>
</div>
</div>
<div class="card-header col-12">Please fill in all fields. </div>
<div class="card-body" formArrayName="inputs">
<div class="row">
<div class="col-6" *ngFor="let contact of contactFormGroup.controls; let i = index;">
<div [formGroupName]="i" class="row z-depth-1 m-1 p-1">
<div class="form-group col-6">
<input class="form-control" formControlName="name" type="text" readonly>
</div>
<div class="form-group col-6">
<1-- This is the input that the user will fill in and I am not sure how to dynamically set the type or placeholder this is what I am trying to achieve -->
<input class="form-control" type="" placeholder=""
formControlName="value" />
</div>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
<div class="icon-bar round">
<button class="btn btn-success round m-1" type="submit" (click)="submit()"><i class="fas fa-save"> Save Form</i></button>
</div>
Any help is very much appricated on this I have been trying to figure it out for a while now, thank you

How to use one component for validation other two components?

I have three components: GalleryAddComponent to add a new element, GalleryItemComponent, to edit an element, FieldsComponent, the form I want to use in the components: GalleryAddComponent and GalleryItemComponent. All components are inside the GalleryComponent. But when I go to the component GalleryAddComponent to add a new element I get the error: ERROR TypeError: Cannot read property 'controls' of undefined. Also in the component: GalleryItemComponent.
Help solve this problem so that the editing and adding logic works correctly.
template of GalleryAddComponent
<div class="card">
<div class="card-body">
<form [formGroup]="angForm" novalidate>
<app-fields [formGroup]="angForm"></app-fields>
<div class="form-group but-group">
<button (click)="addPost(title.value, url.value); angForm.reset(title.value, url.value)"
[disabled]="angForm.pristine || angForm.invalid"
class="btn btn-primary">Add
</button>
<a routerLink="/" class="btn btn-danger">Back</a>
</div>
</form>
</div>
</div>
code of GalleryAddComponent
export class GalleryAddComponent implements OnInit {
angForm: FormGroup;
isAdded: boolean = false;
constructor(private fb: FormBuilder, private galleryService: GalleryService) {}
ngOnInit() {
this.angForm = this.fb.group({
title: ['', Validators.required],
url: ['', Validators.required]
});
}
addPost(title: string, url: string): void {
this.galleryService.add(title, url).subscribe(res => {
this.isAdded = true;
});
}
}
template of GalleryItemComponent
<div class="card" *ngIf="toggleEdit">
<h4>Edit your post</h4>
<div class="card-body">
<form [formGroup]="angForm" novalidate>
<app-fields [formGroup]="angForm"></app-fields>
<div class="form-group but-group">
<input type="button"
(click)="updatePost(title.value, url.value)"
[disabled]=" angForm.invalid"
class="btn btn-primary" value="Update Post">
</div>
</form>
</div>
</div>
code of GalleryItemComponent
export class GalleryItemComponent implements OnInit {
pic: Picture;
angForm: FormGroup;
constructor(private route: ActivatedRoute,
private galleryService: GalleryService, private fb: FormBuilder) {}
ngOnInit() {
this.angForm = this.fb.group({
title: ['', Validators.required],
url: ['', Validators.required]
});
this.showPost();
}
showPost(): void {
this.route.params.subscribe(params => {
this.galleryService.getPicture(params['id']).subscribe(res => {
this.pic = res;
this.angForm.setValue({title: res.title, url: res.url})
})
})
}
updatePost(title: string, url: string): void {
this.route.params.subscribe(params => {
this.galleryService.update(title, url, params['id']).subscribe(res => {
if (res.id === this.pic.id) {
this.pic.title = title;
this.pic.url = url;
}
});
});
}
}
template of FieldsComponent
<div [formGroup]="formGroup">
<div class="form-group">
<label class="col-md-4">Picture Title</label>
<input type="text" class="form-control" formControlName="title" minlength="1" #title/>
</div>
<div *ngIf="angForm.controls['title'].invalid && (angForm.controls['title'].dirty || angForm.controls['title'].touched)"
class="alert alert-danger">
<div *ngIf="angForm.controls['title'].errors.required">
Title is required.
</div>
</div>
<div class="form-group">
<label class="col-md-4">Picture Address (url)</label>
<input type="url" class="form-control" formControlName="url" #url pattern="https?://.+"
title="Include http://"/>
</div>
<div *ngIf="angForm.controls['url'].invalid && (angForm.controls['url'].dirty || angForm.controls['url'].touched)"
class="alert alert-danger">
Address(url) is required.
<div *ngIf="angForm.controls['url'].errors.required ">
</div>
</div>
</div>
code of FieldsComponent
export class FieldsComponent implements OnInit {
#Input() formGroup: FormGroup;
constructor() {}
ngOnInit() {}
}
You are getting this error because you are referencing angForms.controls in your FieldsComponent which only has one variable: formGroup.
Simply replace angForms in the template HTML code with formGroup and the issue should be resolved.
<div [formGroup]="formGroup">
<div class="form-group">
<label class="col-md-4">Picture Title</label>
<input type="text" class="form-control" formControlName="title" minlength="1" #title />
</div>
<div *ngIf="formGroup.controls['title'].invalid && (formGroup.controls['title'].dirty || formGroup.controls['title'].touched)"
class="alert alert-danger">
<div *ngIf="formGroup.controls['title'].errors.required">
Title is required.
</div>
</div>
<div class="form-group">
<label class="col-md-4">Picture Address (url)</label>
<input type="url" class="form-control" formControlName="url" #url pattern="https?://.+" title="Include http://" />
</div>
<div *ngIf="formGroup.controls['url'].invalid && (formGroup.controls['url'].dirty || formGroup.controls['url'].touched)"
class="alert alert-danger">
Address(url) is required.
<div *ngIf="formGroup.controls['url'].errors.required ">
</div>
</div>
</div>
I think the easy solution here, is to set up the formgroup in the parent component, and pass it on to the child components as input, hence it is given to the child component before the child component html is loaded.
The other solution I would recommend is to use the Resolve Technique offered by Angular, this allows you to load all data before a component is loaded with a quite straight-forward setup.
Here are some references:
https://www.techiediaries.com/angular-router-resolve/
https://alligator.io/angular/route-resolvers/
Cannot read property 'controls' of undefined. This error can come only coz instead of formGroup you have used angForm. Try replacing it as shared by #Wrokar. Also what I understand is you want to show consolidated error messages. So instead of doing it in html for each formcontrol, you should do it in component.ts and make it more generic, by subscribing to value change of each control like below, and show the consolidated error message.
for (const field in this.formGroup.controls) { // 'field' is a string
const control = this.form.get(field); // 'control' is a FormControl
control.valueChanges.subscribe(
(res) => {
// check if it is pristine, dirty, invalid, touched, pattern match if
any
// you can access control.errors
// create the consolidated list and append it in the list of error
messages
}
)
}
Its better to make it generic coz, tomorrow your form can have additional fields and then you dont have to change you FieldsComponent.

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