angular2: how to use input fields in sub components of forms - forms

Look at my plunkr:
http://plnkr.co/edit/hB34VjxP98uz1iAYS7Dw?p=preview
Name is included in myform.form, but Name1 of component inner is not. How do I include Name1 in myform?
<div class="container">
<div [hidden]="submitted">
<h1>Hero Form</h1>
<form #heroForm="ngForm">
<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control" required
[(ngModel)]="modelname"
name="name" #name="ngModel" >
<div [hidden]="name.valid || name.pristine" class="alert alert-danger">
Name is required
</div>
<inner></inner>
</div>
</form>
{{heroForm.form.value | json}}
</div>
Template of inner.component:
<label for="name">Name1</label>
<input type="text" class="form-control" required
[(ngModel)]="modelname1"
name="name1" #name1="ngModel" >
<div [hidden]="name1.valid || name1.pristine" class="alert alert-danger">
Name1 is required
</div>
See this issue:
https://github.com/angular/angular/issues/9600

I have fixed your code to accomplish your end goal. Now both Name and Name1 are included in the form and values are coming up on the display for you
I have created a fork from your plnkr and fixed your code to support your use case. Please take a look : http://plnkr.co/edit/UHkwJ9?p=preview
inner.component.html is changed as :
<label for="name">Name1</label>
<input type="text" class="form-control" required
[(ngModel)]="modelname1" [formModel]="form" [registerModel]="name2"
name="name2" #name2="ngModel" >
<div [hidden]="name2.valid || name2.pristine" class="alert alert-danger">
Name1 is required
</div>
hero-form.component.ts is changed as :
<inner [form]="heroForm"></inner>
New Directive is added which will register a new control in the existing form reference :
import { Directive, ElementRef, Input, OnInit } from '#angular/core';
import { NgModel, NgForm } from '#angular/forms';
#Directive({
selector: '[formModel]'
})
export class FormModelDirective implements OnInit {
private el: HTMLInputElement;
#Input('formModel') public form: NgForm;
#Input('registerModel') public model: NgModel;
constructor(el: ElementRef) {
this.el = el.nativeElement;
}
ngOnInit() {
if (this.form && this.model) {
this.form.form.addControl(this.model.name, this.model.control);
}
}
}
Output Image :
Output of the plnkr code
Reference : plnkr.co/edit/GG2TVHHHGbAzoOP5mIRr?p=preview

Related

angular 5 form with form builder

I am trying to implement a form in Angular5. But there occurs a error in the console which states 'formGroup needs to have an instance of FormGroup'
This is the HTML code:
<form [formGroup]="userInfo" (ngSubmit)="onSubmit()" novalidate>
<div class="input-section">
<div class="form-group filled-form">
<label for="businessName">What positions are you hiring for?</label>
<input class="form-control myInputStyle" type="text" id="enterEmail"
formControlName="businessname" required>
<div [hidden]="userInfo.controls['businessname'].valid ||
userInfo.controls['businessname'].pristine" class="inline-error">
Please enter a Business name!
</div>
</div>
</div>
</form>
Here is the ts code :
export class HwaPreviewComponent implements OnInit {
public userInfo:FormGroup;
constructor(private router: Router) { }
ngOnInit() {
}
onSubmit() {
if (this.userInfo.valid) {
console.log("Form Submitted!");
}
}
public userInfo:FormGroup; - adding this in the .ts file helped

Why validation is not working?

corporate.html
<form #f="ngForm" name="corporateProfileForm" ng-submit="corporateFrmSave(objDS, objDSCurrency)" novalidate="">
<div class="row form-group">
<div class="col-md-12" >
<input type="text" *ngIf="formData" [(ngModel)]="formData.Corporate_Id" id="corpid" title="Corporate ID" tab-index="1" name="corpid" maxlength="20" #corpid="ngModel" required/>
<label for="corp"><b>Corporate ID</b></label>
<div *ngIf="corpid.invalid && (corpid.dirty || corpid.touched)" class="alert alert-danger">
<div *ngIf="corpid.errors.required">
Name is required.
</div>
<div *ngIf="ncorpidame.errors.minlength">
Name must be at least 4 characters long.
</div>
<div *ngIf="corpid.errors.forbiddenName">
Name cannot be Bob.
</div>
</div>
</div>
</div>
</form>
Iam getting error message as
ERROR TypeError: Cannot read property 'invalid' of undefined
Make sure you define your variable with this structure:
TS file
export class ContactComponent implements OnInit {
myform: any;
corpid: FormControl;
constructor() {
}
ngOnInit() {
this.createFormControls();
this.createForm();
}
createFormControls() {
this.corpid= new FormControl('', Validators.required);
}
createForm() {
this.myform = new FormGroup({
corpid: this.corpid,
});
}
HTML file
<div class="md-form form-sm form-group"
[ngClass]="{
'invalid': corpid.invalid && (corpid.dirty || corpid.touched),
'valid': corpid.valid && (corpid.dirty || corpid.touched)
}">
<i class="fa fa-user prefix"></i>
<input
type="text" id="corpid" class="form-control"
required
[formControlName]="'corpid'">
<label for="corpid" class="">Your corpid</label>
</div>
<div class="form-control-feedback"
*ngIf="corpid.errors && (corpid.dirty || corpid.touched)">
<p *ngIf="corpid.errors.required">corpid is required</p>
</div>
It's hard to tell because issue is not in your HTML snipped but in .ts file.
I hope my Code will be helpfull
The issue is with the *ngIf, so when that condition is checked, Angular renders the rest of the template, and while the small fraction of time while *ngIf is being evaluated, your template reference variable corpid does not exist, so it will throw an error when trying to check the validation intially.
Wrap the input field with the validation div's inside the *ngIf instead of applying it only on the input field.
<div class="row form-group" *ngIf="formData">
<input [(ngModel)]="formData.Corporate_Id" id="corpid" ... >
<!-- more code here... -->
</div>
DEMO

Angular 2 Template Driven Forms - Array Input Elements

I have been struggling for 1 and half day and still couldn't find any solution to the problem. I am working on simple form which has select and checkboxes element.When I try submitting the form I do not get the values of select and checkboxes but rather I just get true in the console.
I am working on template driven form.
<form (ngSubmit)="addSubcontractor(subcontractorForm)" #subcontractorForm="ngForm">
<h5>Type :</h5>
<div class="form-group">
<div *ngFor="let contractor_type of contractor_types;let i = index;" class="pull-left margin-right">
<label htmlFor="{{ contractor_type | lowercase }}">
{{ contractor_type }} :
</label>
<input type="checkbox" name="_contractor_type[{{i}}]" [value]="contractor_type" ngModel>
</div>
<div class="form-group">
<select class="form-control costcodelist" name="_cc_id[]" multiple="true" ngModel>
//When I put ngModel on select I just keep getting error
//TypeError: values.map is not a function
<option *ngFor="let costcode of costcodes" [selected]="costcode.id == -1" [value]="costcode.id">{{ costcode.costcode_description }}</option>
</select>
</div>
</form>
Component Section
export class SubcontractorComponent implements OnInit, OnDestroy {
private contractor_types = ['Subcontractor', 'Supplier', 'Bank', 'Utility'];
constructor(private costcodeService: CostcodeService,
private subcontractorService: SubcontractorService) {
this.subcontractorService.initializeServices();
}
ngOnInit() {
this.costcode_subscription = this.costcodeService.getAll()
.subscribe(
(costcodes) => {
this.costcodes = costcodes;
});
}
addSubcontractor(form: NgForm) {
console.log(form.value);
}
}
When I remove ngModel from select element the code runs fine and When I submit the form I get the following output.
_contractor_type[0]:true
_contractor_type[1]:true
_contractor_type[2]:true
_contractor_type[3]:""
I do not get the checkboxes values as well the selected options from select element.
Your comments and answer will appreciated a lot.
Thanks
Here is a simple selection that i use with my Template driven form.
<form #f="ngForm" (submit)="addOperator(f.valid)" novalidate>
<label>Name</label>
<input [(ngModel)]="operator.name" name="name">
<label >Service</label>
<select #service="ngModel" name="service" [(ngModel)]="operator.service">
<option *ngFor='let service of services' [ngValue]='service'>{{service.name}}</option>
</select>
<label >Enabled</label>
<label>
<input type="checkbox" name="enabled" [(ngModel)]="operator.enabled">
</label>
<button type="submit">Create Operator</button>
</form>
.ts
operator: Operator;
ngOnInit() {
this.operator = <Operator>{}; // // Initialize empty object, type assertion, with this we loose type safety
}
addOperator(isValid: boolean) {
if (isValid) {
this.operatorsService.addOperator(this.operator).then(operator => {
this.goBack();
});
}
}
Also im importing this
import { FormsModule, ReactiveFormsModule } from '#angular/forms';

Cannot find a differ supporting object '[object Object]' of type, Angular 2

I'm newbie in Angular 2 and trying to write a simple ng-form following by official tutorial.
If I'm using simple array from tutorial, it works fine:
powers = ['Really Smart', 'Super Flexible',
'Super Hot', 'Weather Changer'];
But when I'm changing it on my custom array from http
public departments = [];
constructor(http: Http) {
http.get('/api/departments')
.map((res: Response) => res.json())
.subscribe((departments: Array<Object>) => this.departments = departments);
}
I'm getting an error:
error_handler.js:51 Error: Uncaught (in promise): Error: Error in ./AddClientComponent class AddClientComponent - inline template:41:12 caused by: Cannot find a differ supporting object '[object Object]' of type 'departments'. NgFor only supports binding to Iterables such as Arrays.
So where is my mistake and what am I missing? thanks in advance.
AddClientComponent
import 'rxjs/add/operator/map';
import {Component} from '#angular/core';
import {Http, Response} from '#angular/http';
import { DepartmentsComponent } from '../departments/departments.component';
#Component({
selector: 'app-add-client',
templateUrl: './add-client.component.html',
styleUrls: ['./add-client.component.css']
})
export class AddClientComponent {
public departments = [];
public firstName = '';
public lastName = '';
public id = null;
constructor(http: Http) {
http.get('/api/departments')
.map((res: Response) => res.json())
.subscribe((departments: Array<Object>) => this.departments = departments);
}
model = new Employee(
this.id,
this.firstName,
this.lastName,
this.departments
);
submitted = false;
onSubmit() { this.submitted = true; }
active = true;
}
export class Employee {
constructor(
public id: number,
public firstName: string,
public lastName: string,
public departments: any
) { }
}
html
<div class="container">
<div [hidden]="submitted">
<h1>Employee Form</h1>
<form *ngIf="active" (ngSubmit)="onSubmit()" #employeeForm="ngForm">
<div class="form-group">
<label for="firstName">First Name</label>
<input type="text" class="form-control" id="firstName"
required
[(ngModel)]="model.firstName"
name="firstName"
#firstName="ngModel" >
<div [hidden]="firstName.valid || firstName.pristine"
class="alert alert-danger">
First Name is required
</div>
</div>
<div class="form-group">
<label for="lastName">Last Name</label>
<input type="text" class="form-control" id="lastName"
required
[(ngModel)]="model.lastName"
name="lastName"
#lastName="ngModel" >
<div [hidden]="lastName.valid || lastName.pristine"
class="alert alert-danger">
Last Name is required
</div>
</div>
<div class="form-group">
<label for="departments">Department</label>
<select class="form-control" id="departments"
required
[(ngModel)]="model.departments"
name="departments"
#departments="ngModel" >
<option
*ngFor="let department of departments"
[value]="department">{{department.name}}
</option>
</select>
<div [hidden]="departments.valid || departments.pristine"
class="alert alert-danger">
Department is required
</div>
</div>
<button type="submit"
class="btn btn-default"
[disabled]="!employeeForm.form.valid">Submit
</button>
<!--<button type="button"-->
<!--class="btn btn-default"-->
<!--(click)="newHero()">New Hero-->
<!--</button>-->
</form>
</div>
<div [hidden]="!submitted">
<h2>You submitted the following:</h2>
<div class="row">
<div class="col-xs-3">First Name</div>
<div class="col-xs-9 pull-left">{{ model.firstName }}</div>
</div>
<div class="row">
<div class="col-xs-3">Last Name</div>
<div class="col-xs-9 pull-left">{{ model.lastName }}</div>
</div>
<div class="row">
<div class="col-xs-3">Department</div>
<div class="col-xs-9 pull-left">{{ model.departments }}</div>
</div>
<br>
<button class="btn btn-default" (click)="submitted=false">Edit</button>
</div>
</div>
Use a different name for
#departments="ngModel"
I think it overloads the departments property of the class used in *ngFor
Try changing type
public departments: Array<any> = [];
constructor(http: Http) {
http.get('/api/departments')
.map((res: Response) => res.json())
.subscribe((departments: Array<any>) => this.departments = departments);
}

Angular2 New Form API: Submitting form without any bindings of its elements

Attention: It should work with the new forms API!
Is there a possibility to submit a raw form without any bindings of its elements?
An Example:
<div class="form-mantle">
<form (ngSubmit)="onSubmitForm1(f1.value)" #f1="ngForm">
<input ngControl="name1" name="name1" type="text" required/><br/>
<input ngControl="text1" name="text1" type="text" required/><br/>
<button class="btn btn-primary" [disabled]="!f1.form.valid">Next </button>
</form>
</div>
<pre>
{{ form1 | json }}
</pre>
How should onSubmitForm1() look like, so that I get form1 like below rendered:
{
name1: "Michael Jackson",
text1: "They don't really care about us"
}
I've already preapared a component to copy+paste, for those, who want to help:
import { Component } from '#angular/core';
#Component({
moduleId: module.id,
selector: 'form1',
templateUrl: 'form1.component.html',
styleUrls: ['form1.component.css']
})
export class Form1Component {
form1 : any = {};
constructor() { }
onSubmitForm1 (data?:any) {
// get raw data from form without bindings
this.form1 = data;
console.log("Data", data);
return false;
}
}
Edit: The exact working copy in plnkr (http://plnkr.co/edit/nMPTYLGxgWzzJuD9Be3f?p=preview) does not work within the seed from https://github.com/mgechev/angular2-seed . Maybe it is a version problem ??
Double binding works without errors:
<div class="form-mantle">
<form (ngSubmit)="onSubmitForm1(f1.value)" #f1="ngForm">
<input [(ngModel)]="f1.name1" #name="ngModel" name="name1" type="text" required/><br/>
<input [(ngModel)]="f1.text1" #name="ngModel" name="text1" type="text" required/><br/>
<button class="btn btn-primary" [disabled]="!f1.form.valid">Next </button>
</form>
</div>
<pre>
{{ f1.value | json }}
</pre>
Just call it like so in your ngSubmit:
(ngSubmit)="onSubmitForm1(f1.value)"
To every control you want to submit add the ngControl attribute to set its name:
<input ngControl="name1" name="name1" type="text" required/><br/>
<input ngControl="text1" name="text1" type="text" required/><br/>
Then in your onSubmitForm1:
onSubmitForm1 (data?:any) {
console.log("Data", data);
this.form1 = data;
}
Plunker for example usage
Yeap, for now (rc4) you have only two ways for accepting a data after submit:
1) model-driven strategy (bindings)
2) template-driven strategy (ngControls)
Finaly the following has worked (double bindings :/ ):
<form (ngSubmit)="onSubmitForm()" #s1="ngForm">
<input [(ngModel)]="step1.name1" [ngModelOptions]="{standalone: true}" type="text" required/><br/>
<input [(ngModel)]="step1.text1" [ngModelOptions]="{standalone: true}" type="text" required/><br/>
<button class="btn btn-primary" [disabled]="!s1.form.valid">Next </button>
</form>