Angular2 ngForm not working - forms

I am trying to do a login form component but I cannot read the form data.
When I try to write username on the console, 'undefined' writes.
Everything seems usual but form data does not come to component.
Below is the html code:
<form (ngSubmit)="onSubmit(myForm)"
#myForm="ngForm"
class="form-signin">
<div class="form-group">
<h2 class="form-signin-heading">Please sign in</h2>
<input type="text"
id="inputUsername"
name="inputUsername"
class="form-control"
placeholder="User Name"
required>
<input type="password"
id="inputPassword"
name="inputPassword"
class="form-control"
placeholder="Password" >
</div>
<button class="btn btn-lg btn-primary btn-block"
type="submit">Sign in</button>
</form>
Component ts:
#Component({
selector: 'signin',
templateUrl: './signin.component.html',
encapsulation: ViewEncapsulation.None
})
export class SigninComponent implements OnInit{
constructor(){}
ngOnInit(){ }
onSubmit(form: NgForm){
console.log(form.value.inputUsername);
}
}
Thanks in advance.

You need to add the ngModel directive to each of the form fields. This registers the form fields to your form.
<input type="text"
id="inputUsername"
name="inputUsername"
class="form-control"
placeholder="User Name"
ngModel
required>

add FormsModule in appmodule.ts
import { FormsModule } from '#angular/forms';
imports: [
FormsModule,
]

Related

Angular2 disable submit button if form is invalid

How can I make submit button disabled, when my form is invalid in Angular2?
Now I use code:
<input type="submit" [disabled]="!registrationForm.valid" value="Zarejestruj">
and this is not working and make form always disabled, also when this is valid.
Any suggestion?
UPDATE:
I found error, in form I have file input and this causes form button failed. Here is my whole code (without validation tips)
<div class="form">
<form [formGroup]="registrationForm" (ngSubmit)="RegisterUser(registrationForm.value)" novalidate>
<div class="form-row">
<input type="text" name="login" placeholder="Nazwa użytkownika" [formControl]="registrationForm.controls['login']">
</div>
<div class="form-row">
<input type="password" name="password" placeholder="Hasło" [formControl]="registrationForm.controls['password']" validateEqual="repeatPassword" reverse="true">
</div>
<div class="form-row">
<input type="password" name="repeatPassword" placeholder="Powtórz hasło" [formControl]="registrationForm.controls['repeatPassword']" validateEqual="password">
</div>
<div class="form-row">
<input type="file" name="avatar" file-model="avatar" [formControl]="registrationForm.controls['avatar']" >
</div>
<div class="form-row submit">
<input type="submit" [disabled]="!registrationForm.valid" value="Zarejestruj">
</div>
</form>
</div>
And registration.component.ts:
/ Imports
import { Component, OnInit } from '#angular/core';
import { FormGroup, FormBuilder, Validators } from '#angular/forms';
#Component({
templateUrl: './app/registration/registration.component.html'
})
// Component class implementing OnInit
export class RegistrationComponent {
registrationForm : FormGroup;
constructor(fb: FormBuilder){
this.registrationForm = fb.group({
'login' : [null, Validators.compose([Validators.required, Validators.minLength(4), Validators.maxLength(12)])],
'password' : [null, Validators.compose([Validators.required, Validators.minLength(6), Validators.maxLength(20)])],
'repeatPassword': [null, Validators.required],
'avatar': [null, Validators.required],
})
}
RegisterUser(value: any){
console.log(value);
}
}
Now the question is: why this does not working?

Angular 4 Form FormArray Add a Button to add or delete a form input row

I am building an app using Angular 4.0.2. How can I add a button to a form to add a new row of input and a delete button for a particular row to delete? I mean that I want a form something like this. I want my form to look something like this:
.
Here is my code:
add-invoice.component.html
<h3 class="page-header">Add Invoice</h3>
<form [formGroup]="invoiceForm">
<div formArrayName="itemRows">
<div *ngFor="let itemrow of itemRows.controls; let i=index" [formGroupName]="i">
<h4>Invoice Row #{{ i + 1 }}</h4>
<div class="form-group">
<label>Item Name</label>
<input formControlName="itemname" class="form-control">
</div>
<div class="form-group">
<label>Quantity</label>
<input formControlName="itemqty" class="form-control">
</div>
<div class="form-group">
<label>Unit Cost</label>
<input formControlName="itemrate" class="form-control">
</div>
<div class="form-group">
<label>Tax</label>
<input formControlName="itemtax" class="form-control">
</div>
<div class="form-group">
<label>Amount</label>
<input formControlName="amount" class="form-control">
</div>
<button *ngIf="i > 1" (click)="deleteRow(i)" class="btn btn-danger">Delete Button</button>
</div>
</div>
<button type="button" (click)="addNewRow()" class="btn btn-primary">Add new Row</button>
</form>
<p>{{invoiceForm.value | json}}</p>
Here is my code for add-invoice.component.ts
import { Component, OnInit } from '#angular/core';
import { FormBuilder, FormControl, FormArray, FormGroup } from '#angular/forms';
#Component({
selector: 'app-add-invoice',
templateUrl: './add-invoice.component.html',
styleUrls: ['./add-invoice.component.css']
})
export class AddInvoiceComponent implements OnInit {
invoiceForm: FormGroup;
constructor(
private _fb: FormBuilder
) {
this.createForm();
}
createForm(){
this.invoiceForm = this._fb.group({
itemRows: this._fb.array([])
});
this.invoiceForm.setControl('itemRows', this._fb.array([]));
}
get itemRows(): FormArray {
return this.invoiceForm.get('itemRows') as FormArray;
}
addNewRow(){
this.itemRows.push(this._fb.group(itemrow));
}
ngOnInit(){
}
}
Here's a shortened version of your code:
When you init your form, you can add one empty formgroup inside your formArray:
ngOnInit() {
this.invoiceForm = this._fb.group({
itemRows: this._fb.array([this.initItemRows()])
});
}
get formArr() {
return this.invoiceForm.get('itemRows') as FormArray;
}
Then the function:
initItemRows() {
return this._fb.group({
// list all your form controls here, which belongs to your form array
itemname: ['']
});
}
Here is the addNewRow and deleteRow functions:
addNewRow() {
this.formArr.push(this.initItemRows());
}
deleteRow(index: number) {
this.formArr.removeAt(index);
}
Your form should look like this:
<form [formGroup]="invoiceForm">
<div formArrayName="itemRows">
<div *ngFor="let itemrow of formArr.controls; let i=index" [formGroupName]="i">
<h4>Invoice Row #{{ i + 1 }}</h4>
<div>
<label>Item Name</label>
<input formControlName="itemname">
</div>
<button type="button" (click)="deleteRow(i)" *ngIf="formArr.controls.length > 1" >
Delete
</button>
</div>
</div>
<button type="button" (click)="addNewRow()">Add new Row</button>
</form>
Here's a
DEMO

templateUrl giving undefined when referring to class properties

While following the tutorial for forms at https://angular.io/docs/ts/latest/guide/forms.html
I keep getting undefined errors whenever referring to any of the properties that are defined in the .ts file as long as I use templateUrl and a seperate .html
When I take the same html and place in the .ts file inside `` in template everything works fine.
So my question is: Does the templateURl file need to define scope somehow? The tutorial doesn't seem to cover anything about it and I assumed that it would get access to the component variables that called it.
import { Component } from '#angular/core';
import { NgForm } from '#angular/forms';
import { Guitar } from './guitar';
#Component({
selector: 'guitar-form',
// template: `
// <div class="container">
// <h1>Guitar Form</h1>
// <form>
// <div class="form-group">
// <label for="brand">Brand</label>
// <select class="form-control" required
// [(ngModel)]="testmodel.brand" name="brand">
// <option *ngFor="let b of brands" [value]="b">{{b}}</option>
// </select>
// TODO: remove this: {{testmodel.brand}}
// </div>
// <div class="form-group">
// <label for="model">Model</label>
// <input type="text" class="form-control" required
// [(ngModel)]="testmodel.model" name="model">
// TODO: remove this: {{testmodel.model}}
// </div>
// <div class="form-group">
// <label for="color">Color</label>
// <input type="text" class="form-control"
// [(ngModel)]="testmodel.color" name="color">
// TODO: remove this: {{testmodel.color}}
// </div>
// <button type="submit" class="btn btn-default">Submit</button>
// </form>
// </div>
// `
templateUrl: 'app/guitar-form.component.html'
})
export class GuitarFormComponent {
brands = ['Fender', 'Gibson', 'Guild', 'Jackson', 'Epiphone', 'Charvel'];
testmodel = new Guitar(69, this.brands[0], 'Stratocaster', 'Black');
submitted = false;
onSubmit() { this.submitted = true; }
// TODO: remove this when we're done
get diagnostic() { return JSON.stringify(this.model); }
}
Funny, the undefined disappeared when I commented it out so I could demonstrate but ironically the diagnostic is no longer working when placed in the html and this was the one aspect that was working earlier. I have verified connectivity on an individual basis...
<div class="container">
<h1>Guitar Form</h1>
<form>
{{ diagnostic }}
<div class="form-group">
<label for="brand">Brand</label>
<select class="form-control" required
[(ngModel)]="testmodel.brand" name="brand">
<option *ngFor="let b of brands" [value]="b">{{b}}</option>
</select>
{{ testmodel.brand }}
</div>
<div class="form-group">
<label for="model">Model</label>
<input type="text" class="form-control" required
[(ngModel)]="testmodel.model" name="model">
TODO: remove this: {{testmodel.model}} -->
</div>
<div class="form-group">
<label for="color">Color</label>
<input type="text" class="form-control"
[(ngModel)]="testmodel.color" name="color">
{{ testmodel.color }}
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
</div>
I think you need to add
moduleId: module.id,
to the #Component({...}) decorator.
See also Angular2 - What is the meanings of module.id in component?

Angular 2: 'ngFormModel' since it isn't a known native property

My error is
EXCEPTION: Error: Uncaught (in promise): Template parse errors:
Can't bind to 'ngFormModel' since it isn't a known native property ("
<h3 class = "head">MY PROFILE</h3>
<form [ERROR ->][ngFormModel]="form" (ngSubmit)="onSubmit(form.value)">
<div class="row">
"): a#3:7
There is no directive with "exportAs" set to "ngForm" ("stname</label>
<input type="text" id="facebook" class="form-control" ngControl="firstname" [ERROR ->]#firstname="ngForm" >
</div>
"): a#9:85
There is no directive with "exportAs" set to "ngForm" ("/label>
<input type="text" id="facebook" class="form-control col-xs-3" ngControl="lastname" [ERROR ->]#lastname="ngForm" >
</div>
My template,
<h3 class="head">MY PROFILE</h3>
<form [ngFormModel]="form" (ngSubmit)="onSubmit(form.value)">
<div class="row">
<div class="form-group">
<label class="formHeading">firstname</label>
<input type="text" id="facebook" class="form-control" ngControl="firstname" #firstname="ngForm">
</div>
<div *ngIf="firstname.touched">
<div *ngIf="!firstname.valid" class="alert alert-danger">
<strong>First name is required</strong>
</div>
</div>
<div class="form-group">
<label class="formHeading">lastname</label>
<input type="text" id="facebook" class="form-control col-xs-3" ngControl="lastname" #lastname="ngForm">
</div>
<div *ngIf="lastname.touched">
<div *ngIf="!lastname.valid" class="alert alert-danger">
<strong>Last name is required</strong>
</div>
</div>
<div class="form-group">
<label class="formHeading">Profilename</label>
<input type="text" id="facebook" class="form-control col-xs-3" ngControl="profilename" #profilename="ngForm">
</div>
<div class="form-group">
<label class="formHeading">Phone</label>
<input type="text" id="facebook" class="form-control col-xs-3" ngControl="phone" #phone="ngForm">
</div>
<div *ngIf="phone.touched">
<div *ngIf="!phone.valid" class="alert alert-danger">
<strong>Phone number is required</strong>
</div>
</div>
<label class="formHeading">Image</label>
<input type="file" name="fileupload" ngControl="phone">
<div class="form-row btn">
<button type="submit" class="btn btn-primary " [disabled]="!form.valid">Save</button>
</div>
</div>
</form>
My Component
import {Component} from '#angular/core';
import { Http, Response, Headers} from '#angular/http';
import {Observable} from 'rxjs/Observable';
import {Subject} from 'rxjs/Subject';
import {contentHeaders} from '../headers/headers';
import {FORM_DIRECTIVES} from '#angular/forms';
import {Router, ROUTER_DIRECTIVES} from '#angular/router';
import {Control, FormBuilder, ControlGroup, Validators} from '#angular/common';
#Component({
templateUrl: './components/profile/profile.html',
directives: [ROUTER_DIRECTIVES, FORM_DIRECTIVES],
})
export class Profile {
http: Http;
form: ControlGroup;
constructor(fbld: FormBuilder, http: Http, public router: Router) {
this.http = http;
this.form = fbld.group({
firstname: ['', Validators.required],
lastname: ['', Validators.required],
profilename: ['', Validators.required],
image: [''],
phone: [''],
});
}
onSubmit(form: any) {
console.log(form);
let body = JSON.stringify(form);
var headers = new Headers();
this.http.post('http://localhost/angular/index.php/profile/addprofile', body, {
headers: headers
})
.subscribe(
response => {
if (response.json().error_code == 0) {
alert('added successfully');
this.router.navigate(['/demo/professional']);
} else {
alert('fail');
}
});
}
}
The problem is that you're still importing from common and especially using the instructions of the old forms.
Import correctly the components for new forms:
import {FORM_DIRECTIVES, REACTIVE_FORM_DIRECTIVES} from '#angular/forms';
import {FormBuilder, FormGroup, Validators} from '#angular/forms';
And correct the component:
#Component({
...
directives: [FORM_DIRECTIVES, REACTIVE_FORM_DIRECTIVES]
})
export class AppComponent {
form: FormGroup;
constructor(fbld: FormBuilder) {
this.form = fbld.group({
...
});
}
...
}
Then correct the view: ngFormModel has been replaced by formGroup, and use formControl for your fields:
<form [formGroup]="form" (ngSubmit)="onSubmit(form.value)">
<div class="row">
<div class="form-group">
<label class="formHeading">firstname</label>
<input type="text" id="facebook" class="form-control" [formControl]="form.controls['firstname']" >
</div>
<div *ngIf ="form.controls['firstname'].touched">
<div *ngIf ="!form.controls['firstname'].valid" class = "alert alert-danger">
<strong>First name is required</strong>
</div>
</div>
...
<div class="form-row btn">
<button type="submit" class="btn btn-primary" [disabled]="!form.valid">Save</button>
</div>
</div>
</form>
Edit. From Angular 2.0.0-rc.5, is necessary to remove the directives from the component and import the form modules in AppModule:
import { FormsModule, ReactiveFormsModule } from '#angular/forms';
#NgModule({
imports: [
...
FormsModule,
ReactiveFormsModule
],
...
bootstrap: [AppComponent]
})
export class AppModule { }
If you use a shared module, do not forget to export them:
#NgModule({
imports: [
...
FormsModule,
ReactiveFormsModule
],
exports: [
...
FormsModule,
ReactiveFormsModule
]
})
export class SharedModule { }
I had the same issue. What I did to solve it:
remove the tag, and add (click)-function to the button
checked my backend: there was an error in some special event... fixed it
Now it doesn't fire twice anymore.
So double check this! You never know...
Just import the following statement in ts,
import {FORM_DIRECTIVES, FormBuilder, Validators, REACTIVE_FORM_DIRECTIVES} from '#angular/forms';
directives: [CORE_DIRECTIVES, ROUTER_DIRECTIVES, FORM_DIRECTIVES, REACTIVE_FORM_DIRECTIVES],
Make the following changes in templates,
<h3 class = "head">MY PROFILE</h3>
<form [ngFormModel]="form" (ngSubmit)="onSubmit(form.value)">
<div class="row">
<div class="form-group">
<label class="formHeading">firstname</label>
<input type="text" id="facebook" class="form-control" [formControl]="form.controls['firstname']">
</div>
<div *ngIf ="firstname.touched">
<div *ngIf ="!firstname.valid" class = "alert alert-danger">
<strong>First name is required</strong>
</div>
</div>
<div class="form-group">
<label class="formHeading">lastname</label>
<input type="text" id="facebook" class="form-control col-xs-3" [formControl]="form.controls['lastname']">
</div>
<div *ngIf ="lastname.touched" >
<div *ngIf = "!lastname.valid" class = "alert alert-danger">
<strong>Last name is required</strong>
</div>
</div>
<div class="form-group">
<label class="formHeading">Profilename</label>
<input type="text" id="facebook" class="form-control col-xs-3" [formControl]="form.controls['profilename']" >
</div>
<div class="form-group">
<label class="formHeading">Phone</label>
<input type="text" id="facebook" class="form-control col-xs-3" [formControl]="form.controls['phone']">
</div>
<div *ngIf ="phone.touched" >
<div *ngIf = "!phone.valid" class = "alert alert-danger">
<strong>Phone number is required</strong>
</div>
</div>
<div class="form-row btn">
<button type="submit" class="btn btn-primary " [disabled]="!form.valid">Save</button>
</div>
Finally do this in your bootstrapping,
import {provideForms, disableDeprecatedForms} from '#angular/forms';
bootstrap(MyDemoApp, [
provideForms(),
disableDeprecatedForms()]);

play scala tuple form with multiple case class mapping in views

I have a form in controller Authentication.scala:
package controllers
import javax.inject._
import play.api._
import play.api.mvc._
import play.api.data._
import play.api.data.Forms._
import play.api.i18n.Messages.Implicits._
import play.api.libs.concurrent.Execution.Implicits.defaultContext
import models.User
import models.UserProfile
/**
* This controller creates an `Action` to handle HTTP requests to the
* application's home page.
*/
#Singleton
class Authentication #Inject() extends Controller {
val registerForm = Form(
tuple(
"user" -> mapping(
"email" -> nonEmptyText,
"password" -> nonEmptyText
)(User.apply)(User.unapply),
"profile" -> mapping(
"firstname"->nonEmptyText,
"lastname"->nonEmptyText,
"gender" -> ignored(0)
)(UserProfile.apply)(UserProfile.unapply))
)
/**
* Create an Action to render an HTML page with a welcome message.
* The configuration in the `routes` file means that this method
* will be called when the application receives a `GET` request with
* a path of `/`.
*/
def login = Action {
Ok(views.html.login())
}
def loginSubmit = Action {
implicit request =>
// val maybeFoo = request.body.asFormUrlEncoded.get("password").lift(0) // returns an Option[String]
// val something = maybeFoo map {_.toString} getOrElse 0
// println(something)
Ok("Hello")
}
def register = Action{
Ok(views.html.register())
}
def registerSubmit = Action{
implicit request =>
registerForm.bindFromRequest.fold(
formWithErrors => {
// binding failure, you retrieve the form containing errors:
println(formWithErrors)
BadRequest(views.html.register())
},
userData => {
/* binding success, you get the actual value. */
Redirect(routes.Authentication.register())
}
)
}
def forgotPassword = Action{
Ok(views.html.forgot_password())
}
}
And I have a view register.scala.html:
#import b3.vertical.fieldConstructor
#(userForm: Form[tuple(Mapping, Mapping)])(implicit messages: Messages)
#main("Register") {
<!-- REGISTRATION FORM -->
<div class="text-center" style="padding:50px 0">
<div class="logo">register</div>
<!-- Main Form -->
<div class="login-form-1">
<form id="register-form" class="text-left" method="POST" action="#routes.Authentication.registerSubmit">
<div class="login-form-main-message"></div>
<div class="main-login-form">
<div class="login-group">
<div class="form-group">
<label for="reg_email" class="sr-only">Email</label>
<input type="text" class="form-control" id="reg_email" name="email" placeholder="email">
</div>
<div class="form-group">
<label for="reg_password" class="sr-only">Password</label>
<input type="password" class="form-control" id="reg_password" name="password" placeholder="password">
</div>
<div class="form-group">
<label for="password_confirm" class="sr-only">Password Confirm</label>
<input type="password" class="form-control" id="password_confirm" name="reg_password_confirm" placeholder="confirm password">
</div>
<div class="form-group">
<label for="firstname" class="sr-only">First Name</label>
<input type="text" class="form-control" id="firstname" name="firstname" placeholder="First Name">
</div>
<div class="form-group">
<label for="lastname" class="sr-only">Last Name</label>
<input type="text" class="form-control" id="lastname" name="lastname" placeholder="Last Name">
</div>
<div class="form-group login-group-checkbox">
<input type="radio" class="" name="gender" id="male" placeholder="username">
<label for="male">male</label>
<input type="radio" class="" name="gender" id="female" placeholder="username">
<label for="female">female</label>
</div>
<div class="form-group login-group-checkbox">
<input type="checkbox" class="" id="reg_agree" name="reg_agree">
<label for="reg_agree">i agree with terms</label>
</div>
</div>
<button type="submit" class="login-button"><i class="fa fa-chevron-right"></i></button>
</div>
<div class="etc-login-form">
<p>already have an account? login here</p>
</div>
</form>
</div>
<!-- end:Main Form -->
</div>
}
I know that I am not sending the form in the parameter for view.html.register(), but the question is how to implement the import in the views, with such a form like that? I am getting error all the time.
Help much appreciated. Thanks
When you create a form using tuple(mapping(...), mapping(...)) the type of the form is a tuple of the mapping's types. So in this case you want the type of the view's form parameter to be Form[(User, UserProfile)].
#(userForm: Form[(User, UserProfile)])(implicit messages: Messages)
#main("Register") {
... HTML ...
}