How can I associate a button with a form using Angular? - javascript

I'm working with Angular 6.x, and I'd like to associate a submit button located outside the form in the DOm with it. That is, I want to accomplish something structurally equivalent to this:
<button type='submit' form='myform'>
click me!
</button>
<form id='myform' action='#' onsubmit='console.log("wheee")'>
<input type='submit' value='me too'/>
</form>
I.e. I want to handle the submit event from the form element.
Is there a way to do this without going through nativeElement or without moving/duplicating the submit handler on the click event of the button?

You can achieve by reference #form of form and passing the same reference to button.
<button type='button' (click)="form.onsubmit()">
click me!
</button>
<form id='myform' #form action='#' onsubmit='console.log("wheee")'>
<input type='submit' value='me too'/>
</form>
Working copy is here - https://stackblitz.com/edit/angular-pnneks

Tyr it like this.
<button type='submit' (click)="myForm.submit()">
click me!
</button>
<form id='myform' action='#' #myForm onsubmit='console.log("wheee")'>
<input type='submit' value='me too'/>
</form>

Well, you could use a Reactive Form and then on the click of this button. call a function that would extract the value of the form and do something on it.
This way, you can also do things like disabling the button if the form is invalid.
So here's what your form will look like:
import { Component } from '#angular/core';
import { FormGroup, FormBuilder, FormControl, Validators } from '#angular/forms';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
userForm: FormGroup;
constructor(private fb: FormBuilder) {}
ngOnInit() {
this.userForm = this.fb.group({
firstName: [, Validators.required],
lastName: [, Validators.required]
});
}
submitForm() {
console.log('Form Submitted with value: ', this.userForm.value);
}
}
And here's the template:
<h3>User Form</h3>
<hr>
<form [formGroup]="userForm">
<div>
<label for="firstName">First Name: </label>
<input type="text" id="firstName" formControlName="firstName">
</div>
<br>
<div>
<label for="lastName">Last Name: </label>
<input type="text" id="lastName" formControlName="lastName">
</div>
</form>
<br>
<button (click)="submitForm()" [disabled]="userForm.invalid">Submit</button>
Here's a Sample StackBlitz for your ref.

Related

Why doesn't react output anything to the console when input is submited?

This is the react code I'm currently using:
import React, { Component } from 'react'
export class AddProduct extends Component {
doSomething(){
console.log('Hello')
}
render() {
return (
<div>
<h3>Product name</h3>
<input type="text" id="product"></input>
<h3>Product price</h3>
<input type="text" id="price"></input>
<input type="submit" id="submit" value="Submit" onSubmit={(e) => {this.doSomething();}}></input>
</div>
)
}
}
export default AddProduct
I'm expecting a 'Hello' output to the terminal when the submit button is pressed however it does not show up. Could anyone help me out?
<input> elements do not fire a submit event when clicked, even when inside a form:
document.querySelector('input').addEventListener('submit', () => {
alert('submit event seen');
});
<form>
<input type="submit">
</form>
A click event would work, though. Change
onSubmit={(e) => {this.doSomething();}}
to
onClick={(e) => {this.doSomething();}}
If your <input> happens to be inside a form, you could attach a submit listener to the form instead.
In order to handle a submit event, you must use a <form /> element.
Example:
import React, { Component } from 'react'
class AddProduct extends Component {
doSomething() {
console.log('Hello')
}
render() {
return (
<form onSubmit={(e) => this.doSomething()}>
<h3>Product name</h3>
<input type="text" id="product" />
<h3>Product price</h3>
<input type="text" id="price" />
<input type="submit" id="submit" value="Submit" />
</form>
);
}
}
export default AddProduct;
See React Form Docs

Angular button is always enabled on form

I have this very basic form, that I am trying to enable/disable a button on if the form is/isn't filled out. When using this form, the button is always enabled even when I add/remove data in the input fields.
<form #activationForm="ngForm">
<input type="email" ([ngModel])="email" placeholder="{{'activation.email' | translate}}" required>
<input type="text" ([ngModel])="code" placeholder="{{'activation.code' | translate}}" required>
<button [disabled]="activationForm.form.invalid" class="button button--success" translate="activation.activate" (click)="activate()"></button>
</form>
#Component({
selector: 'app-activation',
templateUrl: './activation.component.html',
styleUrls: ['./activation.component.scss']
})
export class ActivationComponent {
public email: string = '';
public code: string = '';
}
Why is the button always enabled?
I would suggest using Reactive Forms. There's a cleaner way to do what you want.
Here's an example:
App Module:
import { ReactiveFormsModule } from '#angular/forms';
imports: [
...
ReactiveFormsModule
]
Component TypeScript:
this.activationForm = new FormGroup({
email: new FormControl('', [Validators.required, Validators.email]),
code: new FormControl('', [Validators.required])
});
Component Template:
<form [formGroup]="activationForm" (ngSubmit)="onSubmit($event)">
<input formControlName="email" />
<input formControlName="code" />
<button [disabled]="activationForm.invalid">Submit</button>
</form>
If you're using Angular Material, you can then leverage mat-hint or mat-error to assist with validation messages/hints. You can also make your own, of course.
The bonus with Reactive Forms is that everything is accessible. For example, you can do 'dynamic stuff' with your form by accessing their FormControl with this.activationForm.get('email'). The same goes for the form itself (ex: this.activationForm.setValue(...)). It's pretty powerful and in my opinion, much more preferable than NgForm.
to set two way data binding with ngModel it like this [(ngModel)]="email" also you have to provide name attribute
<form #activationForm="ngForm">
<input type="email" name="email" [(ngModel)]="email" placeholder="{{'activation.email' }}" required>
<input type="text" name="code" [(ngModel)]="code" placeholder="{{'activation.code' }}" required>
<button [disabled]="activationForm.form.invalid" class="button button--success" translate="activation.form.invalid" (click)="activate()">create</button>
</form>
demo 🚀

How to validate template driven form without model driven approach.?

I am trying to validate template driven form in Angular without two way databinding. I have done validation using [(ngModel)] but when i try to validate form without MODEL i get following error
Cannot read property 'invalid' of undefined
This is my HTML code.
<div class="jumbotron">
<div class="container">
<div class="row">
<div class="col-md-6 offset-md-3">
<h3>Angular 6 Template-Driven Form Validation</h3>
<form name="form" (ngSubmit)="onSubmit(f.value)" #f="ngForm" novalidate>
<div class="form-group">
<label for="username">Username:</label>
<input type="text"
class="form-control"
name="username"
#userName
required
minlength="8"/>
<div *ngIf="f.form.controls.username.invalid && f.form.controls.username.touched" class="invalid-feedback">
<div *ngIf="f.form.controls.username.errors.required" class="alert alert-danger">Username is required</div>
<div *ngIf="f.form.controls.username.minlength" class="alert alert-danger">length should b 8 character</div>
</div>
</div>
<button class="btn btn-primary" >Register</button>
</form>
</div>
</div>
</div>
</div>
It also not sending data to component when i click button.
this is component TS file .
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-template-driven-form',
templateUrl: './template-driven-form.component.html',
styleUrls: ['./template-driven-form.component.css']
})
export class TemplateDrivenFormComponent {
// model: any = {};
onSubmit(f) {
// alert('SUCCESS!! :-)\n\n' + f);
console.log(f);
}
}
Just replace:
f.form.controls.username.invalid
with
username.invalid
but its mandatory to use ngModel
so your HTML control:
<input type="text" ngModel class="form-control" name="username" #username="ngModel" required minlength="8"/>
It's not working because it shouldn't.
As you can see, inputs that aren't bound with ngModel aren't part of your form.
So simply use ngModel and you should be good to go.

How to normally bind forms in angular

I have a template form, which I wrote from guides and they don't really work though.
I have several of models:
export class User {
constructor(public userId?: UserId,
public firstName?: String,
public lastName?: String,
public address?: Address) {
}
}
export class Address {
constructor(
public street?: String,
public city?: String,
public zipCode?: String) {
}
}
I have component:
Component({
templateUrl: 'user.html'
})
export class MyComponent implements OnInit, OnDestroy{
user: User;
userForm: NgForm;
ngOnInit(): void {
}
And page itself:
<form novalidate #userForm="ngForm">
<div class="form-group">
<input required minlength="4" type="text"
id="firstName"
[(ngModel)]="user.firstName" name="firstName">
<small *ngIf="!firstName.valid">Not valid!</small>
</div>
<div class="form-group">
<input required ng-minlength="4" type="text"
id="lastName"
[(ngModel)]="user.lastName" name="lastName">
</div>
<div ngModelGroup="user.address">
<div class="form-group">
<input required ng-minlength="4"
type="text"
id="address-house"
[(ngModel)]="user.address.address1" name="address.address1">
</div>
<div class="form-group">
<div class="form-group">
<input required ng-minlength="4"
type="text"
id="zipCode"
[(ngModel)]="user.address.zipCode" name="address.zipCode">
</div>
<div>
<input required ng-minlength="4"
type="text"
lass="form-control input-lg"
id="city"
[(ngModel)]="user.address.city" name="address.city">
</div>
</div>
</div>
<button type="button" (click)="checkAndProceed()">Continue</button>
</div>
</form>
The only thing I want to do is to add validation - that's all. None of the guides helped. Can we do in-html validation or ts validation? It would be nice to call validation when clicking 'Continue' button and making it valid if it is so.
In this case of validation I additionally get console error:
Cannot read property 'valid' of undefined
There are lots of attributes on input elements. We have name, Id, and template reference variable. Your code is missing the template reference variable. It is the template reference variable that holds onto the reference to the element and has the valid, dirty, and other flags associated with it.
For example, change your code to include a template reference variable like this:
<div class="form-group">
<input required minlength="4" type="text"
id="firstName"
[(ngModel)]="user.firstName" name="firstName"
#firstNameVar="ngModel">
<small *ngIf="!firstNameVar.valid">Not valid!</small>
</div>
Notice the #firstNameVar. That is the template reference variable. It can be named the same thing as your Id and name attributes. I just named it something different so it could be readily distinguished between the other two attributes.
Notice also that the *ngIf is then changed to use firstNameVar.valid
For more information on template reference variables, see this: https://angular.io/guide/template-syntax#ref-vars

Angular 2 Form Validation For Numbers minimum and maximum

I have a form with input boxes. The input boxes are in both type text and numbers. And I have to validate them and I followed this tutorial and tried to validate them.
According to that if I have to validate a string then I can use the control group as follows.
constructor(fb: FormBuilder){
this.complexForm = fb.group({
'firstName' : [null, Validators.required],
'lastName': [null, Validators.compose([Validators.required, Validators.minLength(5), Validators.maxLength(10)])]
})
And the HTML code for this as follows...
<form [formGroup]="complexForm" (ngSubmit)="submitForm(complexForm.value)">
<div class="form-group">
<label>First Name:</label>
<input class="form-control" type="text" placeholder="John" [formControl]="complexForm.controls['firstName']">
</div>
<div class="form-group">
<label>Last Name</label>
<input class="form-control" type="text" placeholder="Doe" [formControl]="complexForm.controls['lastName']">
</div>
<div class="form-group">
<button type="submit" class="btn btn-default">Submit</button>
</div>
</form>
But I have to validate a number type input box also as the following example.
<form [formGroup]="complexForm" (ngSubmit)="submitForm(complexForm.value)">
<div class="form-group">
<label>Age:</label>
<input class="form-control" type="number" [formControl]="complexForm.controls['age']">
</div>
<div class="form-group">
<button type="submit" class="btn btn-default">Submit</button>
</div>
</form>
But Problem is there is no option for Validators to select what is minimum value and maximum value for the input.
are there someone has a solution for this issue?
Thanks.
The current version of angular 4 now has min and max validators
So it is as simple as writing
this.complexForm = fb.group({
age:[null,[Validators.required, Validators.min(5),Validators.max(90)]],
})
Remember it is on the #angular/forms repo
$: npm uninstall #angular/forms --save
$: npm install #angular/forms --save
There's no built-in Validator for min/max currently you can checkout the source for Validator to see whats available.
What you can do is create a custom validator function following the tutorials in the official docs
Example:
export function maxValue(max: Number): ValidatorFn {
return (control: AbstractControl): {[key: string]: any} => {
const input = control.value,
isValid = input > max;
if(isValid)
return { 'maxValue': {max} }
else
return null;
};
}
With this you can update your code to
constructor(fb: FormBuilder){
this.complexForm = fb.group({
'firstName' : [null, Validators.required],
'lastName': [null, Validators.compose([Validators.required, Validators.minLength(5), Validators.maxLength(10)])],
'age': [null, maxValue(60)]
})
If I get your issue right, try to include your validators' requirements also in HTML so your code will look as follows:
<form [formGroup]="complexForm" (ngSubmit)="submitForm(complexForm.value)">
<div class="form-group">
<label>Age:</label>
<input class="form-control" type="number" required minlength="5" maxlength="10" [formControl]="complexForm.controls['age']">
</div>
<div class="form-group">
<button type="submit" class="btn btn-default">Submit</button>
</div>
</form>
not sure if this is what you are looking for but HTML validators are always an option
<input type="number">
This won't allow users to put in anything but numbers and you don't have to parse it as it will be set as a number not a string.

Categories