I am new to Angular 2. So, I have this form where I created with Angular 2, and bootstrap. So, when you click on the text field and move the mouse else where, the box turns red (which is good). But, when they click on submit button, it when the form is empty, it won't show the "required" dialog. So, please check my code of what I did wrong. Thank you!
I want to show this when they click on a empty form:
Here is the code.
<div class="col-md-8 col-md-offset-2">
<form (ngSubmit)="onSubmit(form)" #form="ngForm">
<div class="form-group">
<label for="content">Content</label>
<input type="text"
id="content"
class="form-control"
ngModel
name="content"
required>
</div>
<button class="btn btn-primary" type="submit">Save</button>
</form>
</div>
Second Part:(TypeScript)
import { Component } from "#angular/core";
import {MessageService} from "./message.service";
import {Message} from "./message.model";
import {NgForm} from "#angular/forms";
#Component({
selector: 'app-message-input',
templateUrl: './message-input.component.html'
})
export class MessageInputComponent {
constructor(private messageService: MessageService) {}
onSubmit(form: NgForm) {
const message = new Message(form.value.content, 'John');
this.messageService.addMessage(message);
form.resetForm();
}
}
I fixed my answer by enabling the default HTML validation. Becuase for some reason in Angular, the default HTML validation is disabled by Angular. So, I enabled it by doing:
<div class="col-md-8 col-md-offset-2">
<form ngNativeValidate (ngSubmit)="onSubmit(f)" #f="ngForm">
<div class="form-group">
<label for="content">Content</label>
<input
type="text"
id="content"
class="form-control"
ngModel
name="content"
required>
</div>
<button class="btn btn-primary" type="submit">Save</button>
</form>
I just add ngNativeValidate in my form tags.
Related
I need your help!I am newbie in Angular Reactive Forms and I am trying to make simple form with validation using Angular's Reactive Forms. But I get an error in this part of my code (ngIf directive, property 'invalid'):
<div class="container">
<form class="card" [formGroup]="form" (ngSubmit)="submit()">
<h1>Angular Forms</h1>
<div class="form-control">
<label>Email</label>
<input type="text" placeholder="Email" formControlName="email">
<div
*ngIf="form.get('email').invalid"
class="validation">
</div>
</div>
<div class="form-control">
<label>Пароль</label>
<input type="password" placeholder="Пароль" formControlName="password">
<div class="validation"></div>
</div>
<div class="card">
<h2>Адрес</h2>
<div class="form-control">
<label>Страна</label>
<select>
<option value="ru">Россия</option>
<option value="ua">Украина</option>
<option value="by">Беларусь</option>
</select>
</div>
<div class="form-control">
<input type="text">
</div>
<button class="btn" type="button">Выбрать столицу</button>
</div>
<div class="card">
<h2>Ваши навыки</h2>
<button class="btn" type="button">Добавить умение</button>
<div class="form-control">
<label></label>
<input type="text">
</div>
</div>
<button class="btn" type="submit" [disabled]="form.invalid">Отправить</button>
</form>
</div>
TypeScript code:
import { Component, OnInit } from '#angular/core';
import { FormControl, FormGroup, Validators } from '#angular/forms';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.less']
})
export class AppComponent implements OnInit {
title = 'forms';
form!: FormGroup;
ngOnInit() {
this.form = new FormGroup({
email: new FormControl('',
[Validators.email,
Validators.required]),
password: new FormControl(null,
[Validators.required,
Validators.minLength(8)])
})
}
submit() {
console.log('Form submitted', this.form);
const formData = { ...this.form.value };
console.log('Form Data:', formData);
}
}
I use Angular 12 and I followed guide on Udemy, so this is very strange, because my mentor's code works correct. I created FromGroup and FormControls, gave them names, so I am really confused about this error. Do you have any ideas how can I fix it?
The Object is possibly 'null' error can happen due to strict type checking and can be solved in 2 ways:
Either assert that you are absolutely sure that can never be null, by using the ! (not null assertion operator)
Use the ? (optional chaining operator) to stop an eventual error from happening in case the object is indeed null
So you can replace the if statement with form.get('email')?.invalid and it should work. A similar question has been asked here.
but I got this error,
Object is possibly 'null
<span *ngIf="name.errors.minlength">You must enter atleast 3 characters
why my error object is always null,minlength is not store in my error object what is the reason for that?
My hero.ts file is,
export class Hero {
constructor(
public id: number,
public name: string,
public email: string
) { }
}
My formone.component.ts file is,
import { Component, OnInit } from '#angular/core';
import {NgForm} from "#angular/forms";
import {Hero} from "../../hero"
#Component({
selector: 'app-formone',
templateUrl: './formone.component.html',
styleUrls: ['./formone.component.css']
})
export class FormoneComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
model = new Hero(1, 'chamara','chamara#gmail.com');
submitted = false;
onSubmit() { this.submitted = true; }
get diagnostic() { return JSON.stringify(this.model); }
}
My formone.component.html file is,
<div class="container mt-3">
<div class="row">
<div class="col-md-2">
</div>
<div class="col-md-8">
<h4>Template Driven Forms</h4>
<form #formone="ngForm" (ngSubmit)="onSubmit()">
{{diagnostic}}
<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control" id="name"
required
[(ngModel)]="model.name" name="name" #name="ngModel" minlength="3" #x>
</div>
<div *ngIf="!name.valid" class="alert alert-danger" >
<span *ngIf="name.errors.minlength">You must enter atleast 3 characters</span>
<span *ngIf="name.errors.required">This field required</span>
</div>
<div class="form-group">
<label for="alterEgo">Email</label>
<input type="email" class="form-control" id="alterEgo"
[(ngModel)]="model.email" name="alterEgo">
</div>
<br>
<button type="submit" class="btn btn-primary" [disabled]="!formone.form.valid">Submit</button>
</form>
</div>
<div class="col-md-2">
</div>
</div>
</div>
Plz help me to fix this,
Your Approach seems to be fine (at least for me), might you need to take care of few things
Remove extra #X from input code (this is causing issue by misleading error checking) and try to add name?.errors?.minlength just cross check name exists while checking errors.
<input type="text" class="form-control" id="name" required
[(ngModel)]="model.name" name="name" #name="ngModel" minlength="3">
<span *ngIf="name?.errors?.minlength">You must enter atleast 3 characters</span>
You can check more about template driven error handling here:
https://medium.com/swlh/form-validation-with-angular-template-driven-forms-8e0756cbec5
Happy Coding.. :)
I have a FormGroup which has three FormControl fields and one FormArray fields as shown in the figure below. The requirement is to take the manager name from user and once add button is pressed, manager details should be displayed in table. In table a remove button is provided, when remove button is pressed manager should be removed form the table and list. When the form is submitted list of managers should be saved. Everything works fine except formArray logic.
I tried to find a solution to this online (followed various links:- https://alligator.io/angular/reactive-forms-formarray-dynamic-fields/,
Angular 4 Form FormArray Add a Button to add or delete a form input row), but did not helped much. There is not much material on how to store formArray in formGroup. Please suggest.
Below is my code, please have a look:-
1. manager-create-modal.component.html
<div>
<form [formGroup]="createForm" (ngSubmit)="onFormCreation()">
<div class="row">
<div class="column">
<div class="form-inline">
<div class="form-group">
<label for="remote_access_method">Remote Access Method: <font color="orange"> *</font> </label>
<input type="text" size='38' class="form-control" formControlName="remote_access_method" >
</div>
</div>
<br>
<div class="form-inline">
<div class="form-group">
<label for="status">Current Status: <font color="orange"> *</font> </label>
<input type="text" size='38' class="form-control" formControlName="status">
</div>
</div>
<br>
<div class="form-inline">
<div class="form-group">
<label for="secregid">Registration ID:<font color="orange"> *</font> </label>
<input type="text" size='38' class="form-control" formControlName="secregid">
</div>
</div>
<br><br>
<div class="form-inline">
<div class="form-group">
<br><br>
<div formArrayName="manager_formArray">
Enter name: <input type="text" class="form-control" formControlName="MgrName" size='50' >
<button type="button" class="btn btn-primary btn-sm" (click)="addPM()">Add</button>
<br><br>
<table class="table table-hover">
<tr><th>#</th><th>Manager Name</th><th>Remove</th></tr>
<tr *ngFor="let pm of createForm.get('manager_formArray').value; let id = index">
<td>{{id+1}}</td>
<td>{{pm.MgrName}}</td>
<td>
<span class="table-remove">
<button type="button" class="btn btn-primary btn-sm" (click)="removeMgr(id)">Remove</button>
</span>
</td>
</tr>
</table>
</div>
</div>
</div>
</div>
<br>
</div>
<br><br>
<div class="form-group">
<button class="btn btn-primary">Submit</button>
</div>
</form>
</div>
2. manager-create-modal.component.ts
import { Component, OnInit } from '#angular/core';
import { FormGroup, FormBuilder, FormArray, FormControl, Validators } from '#angular/forms';
#Component({
selector: 'app-manager-create-modal',
templateUrl: './manager-create-modal.component.html',
styleUrls: ['./manager-create-modal.component.css']
})
export class ManagerCreateModalComponent implements OnInit {
createForm: FormGroup;
manager_formArray: FormArray;
remote_access_method: FormControl;
status: FormControl;
secregid: FormControl;
constructor(private formBuilder: FormBuilder) { }
createFormControls(){
this.remote_access_method = new FormControl('');
this.status = new FormControl('');
this.secregid = new FormControl('');
this.manager_formArray = new FormArray([ this.createItem() ]);
}
createItem(): FormGroup {
return this.formBuilder.group({
MgrName: ''
});
}
createFormVariables(){
this.createForm = new FormGroup({
remote_access_method : this.remote_access_method,
status : this.status,
secregid : this.secregid,
manager_formArray: this.manager_formArray,
})
}
ngOnInit() {
this.createFormControls();
this.createFormVariables();
}
addPM(mgr: any): void {
console.log("inside addPM");
this.manager_formArray.push(this.formBuilder.group({MgrName:''}));
console.log("list after addition:"+this.manager_formArray.value);
for(let i = 0; i < this.manager_formArray.length; i++) {
console.log(this.manager_formArray.at(i).value);
}
}
get managerFormArray() {
return this.manager_formArray.get('MgrName') as FormArray;
}
onFormCreation(){
console.log("success")
}
}
The manager name is not displayed in the table and I keep on getting below error:-
ERROR Error: Cannot find control with path: 'manager_formArray ->
MgrName' at _throwError (forms.js:1731) at setUpControl
(forms.js:1639) at
FormGroupDirective.push../node_modules/#angular/forms/fesm5/forms.js.FormGroupDirective.addControl
(forms.js:4456) at
FormControlName.push../node_modules/#angular/forms/fesm5/forms.js.FormControlName._setUpControl
(forms.js:4961) at
FormControlName.push../node_modules/#angular/forms/fesm5/forms.js.FormControlName.ngOnChanges
(forms.js:4911) at checkAndUpdateDirectiveInline (core.js:9031)
at checkAndUpdateNodeInline (core.js:10299) at
checkAndUpdateNode (core.js:10261) at debugCheckAndUpdateNode
(core.js:10894) at debugCheckDirectivesFn (core.js:10854) inside
addPM manager-create-modal.component.ts:50 list after
addition:[object Object],[object Object]
manager-create-modal.component.ts:53 {MgrName: ""}
manager-create-modal.component.ts:53 {MgrName: ""}
I even don't understand why elements are not getting added to manager_formArray. Please help me out.
You have a few issues. First of all, it is better to move the Input which adds more FormGroups to your FormArray outside of the <div formArrayName="manager_formArray">- element. I created a new FormControl this.mgrNameInput = new FormControl(''); for this reason (see StackBlitz for more details).
You also need to add the message to the new entry when you press the Add-button, calling the addPM()-method:
addPM(){ // removed the argument, using the controller inside the method instead.
this.manager_formArray.push(this.formBuilder.group({MgrName:this.mgrNameInput.value}));
this.mgrNameInput.reset(); // reset the input field.
}
I also added the remove-method when removing an entry.
removeMgr(index: number){
this.manager_formArray.removeAt(index);
}
Please check the StackBlitz for the complete example
Background
I have a form where I give the user the option to specify either a quick time-frame or a detailed one (with a specific start/end time) - i.e. the user has the option to fill only one out of the two
The type of option that they wish to choose can be toggled with the click of a button. These buttons just toggle the hidden parameter on the specified divs
Issue
My problem here is that both of these fields (all 3 technically as start/end time are 2 separate form group divs under one generalized div) are required only if they are not hidden - I am not sure how this can be achieved with Angular 4/5/6 (using 6 here)
My invalid form trigger always goes off as the hidden field is also required
My Form
<div class="card-block">
<form #f="ngForm" (ngSubmit)="onSubmit(f)" novalidate>
<div class="form-group">
<label for="transactionType"> Request Type </label>
<select
class="form-control"
[(ngModel)]=data.transactionType
name ="transactionType"
#transactionType="ngModel"
required>
<option value="something1Count">Something1</option>
<option value="something2Count">Something2</option>
</select>
<div *ngIf="transactionType.errors?.required && transactionType.touched" class="alert alert-danger">
Please select a transaction type
</div>
</div>
<br>
<div class="form-group">
<label>Timeframe Type</label>
<br>
<button type="button" class="btn btn-light" (click)="quickTimeframe = false; detailedTimeframe = true;" ng-selected="!quickTimeFrame"> Quick </button>
<button type="button" class="btn btn-light" (click)="detailedTimeframe = false; quickTimeframe = true;" ng-selected="!detailedTimeframe"> Detailed </button>
</div>
<div class="form-group" [hidden]="quickTimeframe">
<label for="timeframe">Timeframe</label>
<select
class="form-control"
[(ngModel)]=data.timeframe
name ="timeframe"
#timeframe="ngModel"
required>
<option value="15">15 Minutes</option>
<option value="30">30 Minutes</option>
<option value="45">45 Minutes</option>
<option value="60">60 Minutes</option>
</select>
<div *ngIf=" !quickTimeframe && timeframe.errors?.required && timeframe.touched" class="alert alert-danger">
Please select a timeframe
</div>
</div>
<div class="detailed" [hidden]="detailedTimeframe">
<div class="form-group">
<label for="startTime">Start of Time Range</label>
<input
type="datetime-local"
class="form-control"
[(ngModel)]="data.startTime"
#startTime="ngModel"
name="startTime"
required
>
<div *ngIf="!detailedTimeframe && startTime.errors?.required && startTime.touched" class="alert alert-danger">
Please select a start-time
</div>
</div>
<div class="form-group">
<label for="endTime">End of Time Range</label>
<input
type="datetime-local"
class="form-control"
[(ngModel)]="data.endTime"
#endTime="ngModel"
name="endTime"
required
>
<div *ngIf="!detailedTimeframe && endTime.errors?.required && endTime.touched" class="alert alert-danger">
Please select an end-time
</div>
</div>
</div>
<input type="submit" class="btn btn-primary btn-block" value="Submit">
</form>
</div>
</div>
TS File
import { Component, OnInit } from '#angular/core';
import { Inputs } from '../../models/Inputs';
import { Router } from '#angular/router';
import {FlashMessagesService} from 'angular2-flash-messages';
#Component({
selector: 'app-main-form',
templateUrl: './main-form.component.html',
styleUrls: ['./main-form.component.css']
})
export class MainFormComponent implements OnInit {
data:Inputs = {
transactionType:'',
timeframe:null,
startTime:'',
endTime:''
};
quickTimeframe:boolean=true;
detailedTimeframe:boolean=true;
buttonResult:any;
constructor(public router:Router, public flashMessagesService:FlashMessagesService) {
}
ngOnInit() {
}
onSubmit({value, valid}:{value:Inputs, valid:boolean}){
console.log("Quick Time Flag: " +this.quickTimeframe);
console.log("Detailed Time Flag: " +this.detailedTimeframe);
if (valid && !this.quickTimeframe){
console.log("Form is valid");
//Stuff should happen
console.log(value);
} else if (valid && !this.detailedTimeframe) {
console.log(this.data.startTime);
//Other stuff should happen
}
else {
console.log("Form is not valid");
this.flashMessagesService.show('Choose Valid Parameters', {cssClass:'alert-danger', timeout: 4000});
}
}
radioClick() {
console.log(this.buttonResult);
}
}
Report Inputs Interface (for completion's sake)
export interface Inputs {
transactionType?:string;
timeframe?:number;
startTime?:string;
endTime?:string;
}
*ngIf did the trick
Using ngIf instead of hidden ensure that the elements do not exist within the form in my scenario
I have an angular 4 form where I am trying to submit data
HTML Code
<form class="form-horizontal" [formGroup]="signupForm"
(ngSubmit)="onFormSubmit()" >
<fieldset>
<legend>Scheduler</legend>
<!--- Gender Block -->
<div class="form-group">
<label for="scheduleJob">Schedule Job</label>
<input type="text" formControlName = "schedulejob"
id="scheduleJob"
placeholder="Schedule Job">
Button code
<div class="form-group">
<button type="reset" class="btn btn-default">Cancel</button>
<button type="submit" class="btn btn-primary">Submit</button>
</div>
Scheduler.TS file
import { Component, OnInit } from '#angular/core';
import { Scheduler } from 'rxjs/Scheduler';
/* Import FormControl first */
import { FormBuilder, FormGroup, Validators } from '#angular/forms';
#Component({
selector: 'app-scheduler',
templateUrl: './scheduler.component.html',
styleUrls: ['./scheduler.component.css']
})
export class SchedulerComponent implements OnInit {
//Gender list for the select control element
private scheduleTypeList: string[];
//Property for the user
private scheduler:Scheduler;
private signupForm: FormGroup;
constructor(private fb:FormBuilder) { }
ngOnInit() {
this.scheduleTypeList = ['Type 1', 'Type 2', 'Type 3'];
this.signupForm = this.fb.group({
schedulejob: ['', Validators.required] ,
frequency: ['', Validators.required],
days: ['', Validators.required],
zone: ['', Validators.required],
schedulerjobtype:['', Validators.required]
})
}
public onFormSubmit() {
this.scheduler = this.signupForm.value;
if(this.signupForm.valid) {
this.scheduler = this.signupForm.value;
console.log(this.scheduler);
// alert(this.scheduler);
/* Any API call logic via services goes here */
}
//alert(this.scheduler);
console.log(this.scheduler);
}
}
Why is the execution not passed to onFormSubmit on submit click and alert or console.log not printing values?
Like I said in the comment, if your button is not inside your form it will not submit it.
So change to:
<form>
...
<button type="submit">Submit</button>
</form>
It is possible however to have it outside if you do it a bit differently, as described in this question.
I was having the same issue because I was not using a <form> tag to wrap my form.
a small trick you can do is to place an auxiliary hidden button inside the form and let the main button programmatically click the auxiliary button:
<form [formGroup]="form" (ngSubmit)="submit()">
...
<button type="submit" hidden #btn></button>
</form>
...
<button (click)="btn.click()">Submit</button>
you need to put the button code inside the form like below
<form class="form-horizontal"
[formGroup]="signupForm"
(ngSubmit)="onFormSubmit()" >
<fieldset>
<legend>Scheduler</legend>
<!--- Gender Block -->
<div class="form-group">
<label for="scheduleJob">Schedule Job</label>
<input type="text" formControlName = "schedulejob"
id="scheduleJob"
placeholder="Schedule Job">
<!-- Button Code Here -->
<div class="form-group">
<button type="reset" class="btn btn-default">Cancel</button>
<button type="submit" class="btn btn-primary">Submit</button>
</div>
<!-- Form ends here -->
</form>
You can also use the form attribute in the submit button. This attribute uses the form's id to refer to it:
<form id="formID">
...
<button type="submit" form="formID">Submit</button>
</form>