Angular reactive FormGroup is not reset in third party controls - angular6

I am using Angular6 and angular material stepper. There are three flows in which stepper control have one form and second stepper control have 2 input fields.
When i have entered the firstStepperCtrl and navigate to second stepper and click on prev and come to second stepper which shows the validation.
Without touching the form , the validation is showing , how to reset the stepper and validate the stepper if second form field has been touched.
Here is the mark up:
<md-horizontal-stepper [linear]="isLinear" #stepper>
<md-step [stepControl]="firstFormGroup">
<form [formGroup]="firstFormGroup">
<ng-template mdStepLabel>Fill out your name</ng-template>
<md-form-field>
<input mdInput placeholder="Last name, First name" formControlName="firstCtrl" required>
</md-form-field>
<div>
<button md-button mdStepperNext>Next</button>
</div>
</form>
</md-step>
<md-step [stepControl]="secondFormGroup">
<form [formGroup]="secondFormGroup" #formDirective="ngForm">
<ng-template mdStepLabel>Fill out your address</ng-template>
<md-form-field>
<input mdInput placeholder="Address" formControlName="secondCtrl" required>
</md-form-field>
<md-form-field>
<input mdInput placeholder="phoneNo" formControlName="secondCtrlPhoneNo" required>
</md-form-field>
<div>
<button md-button mdStepperPrevious>Back</button>
<button md-button mdStepperNext>Next</button>
<button md-button (click)="resetWholeStepper(stepper)">Reset</button>
<button md-button (click)="reset2Stepper()">Reset1</button>
</div>
</form>
</md-step>
<md-step>
<ng-template mdStepLabel>Done</ng-template>
You are now done.
<div>
<button md-button mdStepperPrevious>Back</button>
<button md-button (click)="resetStepper(stepper)">Reset</button>
</div>
</md-step>
</md-horizontal-stepper>
app.component.ts
export class AppComponent implements OnInit, AfterViewInit {
private ngVersion: string = VERSION.full;
isLinear = false;
firstFormGroup: FormGroup;
secondFormGroup: FormGroup;
constructor(private _formBuilder: FormBuilder,) { }
// Event fired when component initializes
ngOnInit() {
this.firstFormGroup = this._formBuilder.group({
firstCtrl: ['', Validators.required]
});
this.secondFormGroup = this._formBuilder.group({
secondCtrl: ['', Validators.required],
secondCtrlPhoneNo:['',Validators.required]
});
}
// Event fired after view is initialized
ngAfterViewInit() {
}
resetWholeStepper(stepper: MdStepper){
stepper.selectedIndex = 0;
}
reset2Stepper1(formDirective: FormGroupDirective){
alert(2);
formDirective.resetForm();
// this.secondFormGroup.clearValidators();
this.secondFormGroup.reset();
}
[screencast link of issue]]1
demo

Related

Refresh input type file

I'm working on an Angular project.
When I import several documents I have the message "two documents". nothing problematic.
The problem arises when I press the delete button that I created.
It allows to empty my list but to display there is always written "two documents"
I wish I had that. like when we get to the page for the first time ("no file selected") :
How could I do to reload this input without reloading the page?
My code :
html :
<div class="form-group">
<label for="pj">Pièce jointe</label>
<div fxLayout="row wrap" fxLayoutAlign="start center">
<input type="file" name="pj" id="pj" (change)="onFileChange($event)" multiple>
<button type="button" (click)="clearFile()" class="btn btn-link">
<i class="fas fa-trash fa-lg"></i>
</button>
</div>
</div>
ts :
clearFile() {
this.message.files = null;
}
Thanks
If you use a reactive form, you can just call reset() on the form control.
component.html
<form [formGroup]="form">
<input type="file" multiple formControlName="files" />
<button type="button" (click)="clearFile()">
Delete
</button>
</form>
component.ts
form: FormGroup;
ngOnInit() {
this.form = new FormGroup({
files: new FormControl('')
});
}
clearFile() {
this.form.get('files').reset();
}
DEMO: https://stackblitz.com/edit/angular-huvm38
you can use ViewChild to access the input in your component. First, you need to add #someValue to your input so you can read it in the component:
<input #myInput type="file" name="pj" id="pj" (change)="onFileChange($event)" multiple>
Then in your component you need to import ViewChild from #angular/core:
import { ViewChild } from '#angular/core';
Then you use ViewChild to access the input from template:
// ng 8 #ViewChild('myInput', {static: false}) myInput: ElementRef;
#ViewChild('myInput') myInput: ElementRef;
Now you can use myInput to reset the selected file because it's a reference to input with #myInput, for example create method reset() that will be called on click event of your button:
reset() {
console.log(this.myInput.nativeElement.files);
this.myInput.nativeElement.value = "";
console.log(this.myInput.nativeElement.files);
}

How to implement a pseudo event for a custom component in Angular?

I have a custom component that contains an input and a button like this
<div class="input-group">
<input type="text" class="form-control form-control-sm"
(input)="change($event)"
ngbDatepicker #d="ngbDatepicker" required
#datef />
<div class="input-group-append">
<button type="button" class="btn btn-sm btn-success" (click)="d.toggle()" type="button">
<i class="fa fa-calendar"></i>
</button>
</div>
</div>
I'd like it to have some funcionality so when the user press enter on the input it should emit a pseudo event
<custom-datepicker (keyup.enter)="handleKeyboard($event)"></custom-datepicker>
I've tried with #HostListener, but I'm getting errors about too much recursion, please, help me
You can just simple use the concept of event emitters wherein you can emit an event from your custom component to your parent component
----Custom Component Html----
<div class="input-group">
<input type="text" class="form-control form-control-sm"
(input)="change($event)"
ngbDatepicker #d="ngbDatepicker" required
#datef />
<div class="input-group-append">
<button type="button" class="btn btn-sm btn-success" (click)="d.toggle()" type="button">
<i class="fa fa-calendar"></i>
</button>
</div>
----Custom Component ts----
#Output()
customEvent = new EventEmitter();
change(event) {
this.customEvent.emit();
}
----Parent Component ----
<custom-datepicker (customEvent)="handleKeyboard($event)"></custom-datepicker>
You can approach this using Reactive Forms FormArray. You would attach an (keyup) or (keyup.enter) handler to the <input />. Within the handler for this keyup event, we push a new FormControl to a FormArray. This example uses FormBuilder to generate a FormGroup that contains a FormArray with a key of things. We use the push method of FormArray to add a new FormControl/AbstractControl within the handler for keyup.
Component:
import { Component } from '#angular/core';
import { FormBuilder, FormGroup, FormArray } from '#angular/forms';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
name = 'Angular';
myForm: FormGroup;
constructor(private fb: FormBuilder) {
this.createForm();
}
onEnter() {
this.addThing();
}
get things() {
return this.myForm.get('things') as FormArray;
}
private createForm() {
this.myForm = this.fb.group({
things: this.fb.array([
// create an initial item
this.fb.control('')
])
});
}
private addThing() {
this.things.push(this.fb.control(''));
}
}
Template:
<form [formGroup]="myForm">
<div formArrayName="things">
<div *ngFor="let thing of things.controls; let i=index">
<label [for]="'input' + i">Thing {{i}}:</label>
<input type="text" [formControlName]="i" [name]="'input' + i" [id]="'input' + i" (keyup.enter)="" />
</div>
</div>
</form>
At a very basic level you can loop through each in the form array using the controls property of the respective FormArray element and the value using the value property:
<ul>
<li *ngFor="let thing of things.controls">{{thing.value}}</li>
</ul>
Here is a StackBlitz(https://stackblitz.com/edit/angular-r5zmbg) demonstrating the functionality.
Hopefully that helps!

Angular: Submit method executed by clicking another button

I'm using Angular with Angular Material components.
So, I added a login component (form) where the user can type in his email and password. The input field for the password has an eye on the end to enable the user to display the password in plain text if wanted.
Unfortunately, by clicking twice the eye button, the submit method executes which is binded to the submit button.
The simple question is: why?
Template
<form [formGroup]='loginForm' (ngSubmit)="onSubmit()">
<div>
<mat-form-field>
<mat-label for="email">E-Mail</mat-label>
<input matInput type="text" formControlField="email" />
<mat-error>
Test
</mat-error>
</mat-form-field>
</div>
<div>
<mat-form-field>
<mat-label for="password">Password</mat-label>
<input matInput [type]="hide ? 'password' : 'text'" formControlField="password" />
<button mat-icon-button matSuffix class="mat-icon-button mat-button-base" (click)="hide = !hide" [attr.aria-label]="'Hide password'" [attr.aria-pressed]="hide">
<mat-icon>{{ hide ? 'visibility_off' : 'visibility' }}</mat-icon>
</button>
</mat-form-field>
</div>
<button mat-raised-button color="primary" type="submit">Login</button>
Component
export class LoginComponent implements OnInit {
loginForm: FormGroup;
hide = true;
constructor(
private formBuilder: FormBuilder
) {
this.loginForm = this.formBuilder.group({
email: ['', [Validators.required, Validators.email]],
password: ['', [Validators.required]]
})
}
onSubmit() {
window.alert("Login button clicked");
}
Try adding type="button" to your "eye" button.
This will tell the browser not to treat it as a submit button when inside a form.
The reason is that missing type argument from button is treated as default state and by default button element has submit.
The missing value default and invalid value default are the Submit Button state.
Source: https://html.spec.whatwg.org/multipage/form-elements.html#attr-button-type

ngSubmit not working

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>

html5 validation in Ionic

I am learning Ionic at the time. But it seems like HTML5 validation is not working in Ionic.
So, i have a login form like below.
<h3> Login </h3>
<form>
<input name="emailaddress" placeholder="Enter Email Address" class="email" [(ngModel)]="userData.l_email" type="email" required />
<input name="name" placeholder="Enter Password" class="name" type="password" [(ngModel)]="userData.l_password" required />
<button class="semi-transparent-button is-blue with-border" (click)="login()">
Login
</button>
</form>
When i click on login button it didn't perform validation. As i have put required in both field but it simply submit the form.
Also email validation is not working.
I have checked How can I make validation of email in Ionic using HTML5, JS or Angular work? but it is a work around. That i want to avoid.
HTML5 form validation does not work in Ionic. Instead, you can use Angular forms.
This is a great tutorial by Josh Morony on how to do it.
In your case, you can do something like this using FormBuilder and specifying Validators for each field (for a full list of available validators, take a look at the docs).
import { Component } from '#angular/core';
import { Validators, FormBuilder, FormGroup } from '#angular/forms';
#Component({
selector: 'page-login',
templateUrl: 'login.html'
})
export class Login {
login: FormGroup;
submitted: boolean = false;
constructor(public formBuilder: FormBuilder) {
this.login = this.formBuilder.group({
email: ['', Validators.compose([Validators.email, Validators.required])],
password: ['', Validators.required],
});
}
onLogin() {
this.submitted = true;
if (this.login.valid) {
console.log(this.login.value);
}
}
}
In your template, use FormGroup and show your error message when the field is invalid.
<form [formGroup]="login" (ngSubmit)="onLogin()">
<ion-item>
<ion-label>Email</ion-label>
<ion-input type="email" formControlName="email"></ion-input>
</ion-item>
<p ion-text [hidden]="login.controls.email.valid || submitted === false" color="danger" padding-left>
Please enter a valid email
</p>
<ion-item>
<ion-label>Password</ion-label>
<ion-input type="password" formControlName="password"></ion-input>
</ion-item>
<p ion-text [hidden]="login.controls.password.valid || submitted === false" color="danger" padding-left>
Password is required
</p>
<button ion-button type="submit">Login</button>
</form>