I had a simple template with a fromGroup and bunch of form controls, and I'm trying to enable a button if the form is valid.
.ts:
import {Component, OnInit} from '#angular/core';
import {FormBuilder, FormControl, FormGroup, Validators} from '#angular/forms';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
formGroup: FormGroup;
constructor(public formBuilder: FormBuilder) {
}
ngOnInit(): void {
this.formGroup = this.formBuilder.group({
firstName: ['', Validators.minLength(3)],
lastName: ['', Validators.minLength(5)]
});
}
}
.html:
<form [formGroup]="formGroup">
<div>
<span>Name</span>
<input type="text" formControlName="firstName">
</div>
<div>
<span>Name</span>
<input type="text" formControlName="lastName">
</div>
<div>
<span>Test</span>
<input [disabled]="!formGroup.valid" type="text">
</div>
</form>
from the above example, the expectation is by default the button should be disabled and once the form is valid I should be able to see the button enabled, and in chrome it is working as expected but not in IE 11 (no errors in the console), looked at few solutions but that hasn't fixed my error, any suggestions ??
Found the solution ChangeDetectorRef.detectChanges(); fixed my issue.
this.formGroup.valueChanges.subscribe(() => {
this.changeRef.detectChanges();
});
Related
I am working on a with nested form groups in Angular 14.
There are form controls common to multiple forms so I have added them in a partial.
In form.component.ts I have:
import { Component } from '#angular/core';
import { FormGroup, FormControl, Validators, FormArray } from '#angular/forms';
#Component({
selector: 'my-app',
templateUrl: './form.component.html',
styleUrls: ['./form.component.css'],
})
export class FormComponent {
public form: FormGroup = new FormGroup({
first_name: new FormControl('', Validators.required),
last_name: new FormControl('', Validators.required),
email: new FormControl('', [Validators.required, Validators.email]),
phone: new FormControl('', Validators.required),
});
constructor() {}
ngOnInit(): void {}
public sendFormData() {
console.log(this.form.value);
}
}
In form.component.html I include the partial <app-additional></app-additional>:
<form [formGroup]="form">
<mat-form-field appearance="outline" floatLabel="always">
<mat-label class="mat-label">Fast name:</mat-label>
<input class="mat-input" matInput formControlName="first_name" />
</mat-form-field>
<mat-form-field appearance="outline" floatLabel="always">
<mat-label class="mat-label">Last name:</mat-label>
<input class="mat-input" matInput formControlName="last_name" />
</mat-form-field>
<app-additional></app-additional>
<div class="center">
<button
(click)="sendFormData()"
mat-raised-button
color="primary"
[disabled]="!form.valid"
>
Submit
</button>
</div>
</form>
See Stackblitz HERE.
The problem
Instead of rendering the partial, the app throws the error:
Error: formControlName must be used with a parent formGroup directive.
Questions:
What causes this problem?
What is the most reliable way to fix it?
You need to pass your form as an input to partial and provide the same form group name over there to make it work.
In form.component.html:
<app-additional [form]="form"></app-additional>
In additional.component.html:
<div class="more-controls" [formGroup]="form">
In additional.component.ts:
#Input() form: FormGroup;
The problem is caused because the form control inside the partial component () is not bound to a parent FormGroup directive.
To fix this problem, you can pass the form FormGroup from the parent component to the partial component using property binding ([form]="form") and bind the form control inside the partial component to the parent FormGroup using formControlName and formGroup directive.
just like this :
<form [formGroup]="form">
<!-- ... -->
<app-additional [form]="form"></app-additional>
<!-- ... -->
</form>
I'd like to link radio buttons inside a form to an object, i cant get it to work!
I am linking ngModel to a variable of type string that is called presentation
I dont know what am I missing? even when i copy a working example it wont work in my form!
here is part of my form that I think is dysfunctional:
HTML:
<div class="uk-margin-large-right">
<div class="uk-flex-inline ">
<span class="uk-form-label uk-margin-small-right uk-text-bold "> Presentation </span>
<label class="uk-margin-medium-right">
<input class="uk-radio " type="radio" name="radio1" value="Cephalic" [(ngModel)]="presentaion"> Cephalic </label>
<label class="uk-margin-medium-right">
<input class="uk-radio" type="radio" name="radio1" value="Breech" [(ngModel)]="presentaion"> Breech </label>
<label class="uk-margin-medium-right">
<input class="uk-radio" type="radio" name="radio1" value="Transverse lie" [(ngModel)]="presentaion"> Transverse lie </label>
</div>
<p>this is {{presentation}}</p>
</div>
Typescript:
import { Component, OnInit } from '#angular/core';
import { CommService } from '../services/comm.service';
#Component({
selector: 'app-form',
templateUrl: './form.component.html',
styleUrls: ['./form.component.css']
})
export class FormComponent implements OnInit {
user = {
Doctor: '',
Patient: '',
Type:'',
Report: ''
};
presentation:'';
constructor(private CommService: CommService) { }
ngOnInit() {
this.CommService.setData(this.user);
console.log(this.presentation);
}
}
Declare it like this if you want to give it initial value
presentaion:string = 'Cephalic';
log() { // log the value to console
console.log(this.presentaion)
}
Template
<p>this is {{presentaion}}</p>
<button (click)="log()">Log the value to console</button>
in your example there was a typo with the property name <p>this is {{presentation}}</p> just change it to presentaion
stackblitz example
So I have a simple login component created with angular like so.
<div class="form">
<form (submit) = "loginUser($event)">
<input type="text" placeholder="username"/>
<input type="password" placeholder="password"/>
<button type = "submit">login</button>
</form>
</div>
On click of this button I want to be able to print the data to the console which is why I added this functionality.
<form (submit) = "loginUser($event)">
This is what my .ts file looks like for that same component.
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-login-form',
templateUrl: './login-form.component.html',
styleUrls: ['./login-form.component.css']
})
export class LoginFormComponent implements OnInit {
constructor() { }
ngOnInit() {
}
loginUser(e){
var username = e.target.elements[0].value;
var password = e.target.elements[1].value;
console.log(username,password);
}
}
When I look at the console I don't see the user name and password that was entered. Am I doing something wrong?
<form class="k-form" (ngSubmit)="loginUser()>
<input type="text" [(ngModel)]="username" name="username" placeholder="username">
<input type="password"[(ngModel)]="password" name="password" placeholder="password">
</form>
Component
username: string;
password: string;
loginUser(){
console.log(this.username,this.password);
}
Upon adding e.preventDefault() to the function it seems to work as expected
I'm creating an input text component with angular2. I need to add a class at this control if is valid and if it's required. This is the component:
import { Component, Input } from "#angular/core";
import { NgForm } from '#angular/forms';
#Component({
selector: "input-control",
template: `
<div [class.has-success]="required" class="form-group form-md-line-input form-md-floating-label">
<input [class.edited]="model[property]"
[(ngModel)]="model[property]"
[attr.ngControl]="property"
[name]="property"
type="text"
class="form-control"
id="{{property}}"
value=""
[attr.required]="required">
<label [attr.for]="property">{{label}}</label>
<span class="help-block">{{description}}</span>
</div>
`
})
export class InputControlComponent {
#Input()
model: any;
#Input()
property: string;
#Input()
label: string;
#Input()
description: string;
#Input()
required: boolean;
#Input()
form: NgForm;
}
In the first row of the template I set the "has-success" class if the input is required but I need to set it if it's valid too. Somethig like this:
[class.has-success]="required && form.controls[property].valid"
The html is this:
<form role="form" *ngIf="active" (ngSubmit)="onSubmit(databaseForm)" #databaseForm="ngForm">
<div class="form-body">
<div class="row">
<div class="col-md-6">
<input-control [model]="model" [property]="'code'" [form]="databaseForm" [label]="'#Localizer["Code"]'" [description]="'#Localizer["InsertCode"]'" [required]="true"></input-control>
</div>
<div class="col-md-6">
<input-control [model]="model" [property]="'description'" [form]="databaseForm" [label]="'#Localizer["Description"]'" [description]="'#Localizer["InsertDescription"]'"></input-control>
</div>
</div>
</div>
</form>
I think that you can't use the template-driven form a sub-component and make it be part of a form of the parent component without implementing a custom value accessor with Angular2 prior to version RC2.
See this question:
Angular 2 custom form input
With version RC2+, I think that it's possible out of the box like this:
<form #databaseForm="ngForm">
<input-control name="code" [ngModelOptions]="{name: 'code'}"
[(ngModel)]="model.code"/>
</form>
I am trying to create a login form but it shows the form values 2 times in console at one click and i am not sure where the error was can any one find the error....
my template
div class="login jumbotron center-block">
<h1>Login</h1>
<form #form ="ngForm" (ngSubmit)="onSubmit(form.value)">
<div class="form-group">
<label for="username">Username</label>
<input type="text" ngControl ="email" class="form-control" id="emailh" placeholder="Username">
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" ngControl ="phone" class="form-control" id="phoneh" placeholder="Password">
</div>
<button class="btn btn-default">Submit</button>
</form>
</div>
my component
import { Component } from '#angular/core';
import { Router, ROUTER_DIRECTIVES } from '#angular/router';
import { CORE_DIRECTIVES, FORM_DIRECTIVES } from '#angular/common';
import { Http, Headers } from '#angular/http';
import { contentHeaders } from '../headers/headers';
import {Control,FormBuilder,ControlGroup,Validators} from '#angular/common';
#Component({
directives: [ ROUTER_DIRECTIVES, CORE_DIRECTIVES, FORM_DIRECTIVES ],
templateUrl : "./components/login/login.html",
})
export class Login {
constructor(public router: Router, public http: Http) {
}
onSubmit(form:any) {
console.log(form);
}
}
I am trying to create a login form but it shows the form values 2 times in console at one click and i am not sure where the error was can any one find the error....
I think you need disable the old forms module
import {disableDeprecatedForms, provideForms} from '#angular/forms';
bootstrap(AppComponent, [disableDeprecatedForms(), provideForms()]);
and import forms-related stuff only from #angular/forms instead of #angular/common