Angular: mat-form-field must contain a MatFormFieldControl - javascript

I am trying to add a form field with custom telephone number input control. I used the example of the phone from https://material.angular.io/components/form-field/examples.
Here is the code:
<mat-form-field>
<example-tel-input placeholder="Phone number" required></example-tel-input>
<mat-icon matSuffix>phone</mat-icon>
<mat-hint>Include area code</mat-hint>
</mat-form-field>
import {FocusMonitor} from '#angular/cdk/a11y';
import {coerceBooleanProperty} from '#angular/cdk/coercion';
import {Component, ElementRef, Input, OnDestroy} from '#angular/core';
import {FormBuilder, FormGroup} from '#angular/forms';
import {MatFormFieldControl} from '#angular/material';
import {Subject} from 'rxjs';
/** #title Form field with custom telephone number input control. */
#Component({
selector: 'form-field-custom-control-example',
templateUrl: 'form-field-custom-control-example.html',
styleUrls: ['form-field-custom-control-example.css'],
})
export class FormFieldCustomControlExample {}
/** Data structure for holding telephone number. */
export class MyTel {
constructor(public area: string, public exchange: string, public subscriber: string) {}
}
/** Custom `MatFormFieldControl` for telephone number input. */
#Component({
selector: 'example-tel-input',
templateUrl: 'example-tel-input-example.html',
styleUrls: ['example-tel-input-example.css'],
providers: [{provide: MatFormFieldControl, useExisting: MyTelInput}],
host: {
'[class.example-floating]': 'shouldLabelFloat',
'[id]': 'id',
'[attr.aria-describedby]': 'describedBy',
}
})
export class MyTelInput implements MatFormFieldControl<MyTel>, OnDestroy {
static nextId = 0;
parts: FormGroup;
stateChanges = new Subject<void>();
focused = false;
ngControl = null;
errorState = false;
controlType = 'example-tel-input';
id = `example-tel-input-${MyTelInput.nextId++}`;
describedBy = '';
get empty() {
const {value: {area, exchange, subscriber}} = this.parts;
return !area && !exchange && !subscriber;
}
get shouldLabelFloat() { return this.focused || !this.empty; }
#Input()
get placeholder(): string { return this._placeholder; }
set placeholder(value: string) {
this._placeholder = value;
this.stateChanges.next();
}
private _placeholder: string;
#Input()
get required(): boolean { return this._required; }
set required(value: boolean) {
this._required = coerceBooleanProperty(value);
this.stateChanges.next();
}
private _required = false;
#Input()
get disabled(): boolean { return this._disabled; }
set disabled(value: boolean) {
this._disabled = coerceBooleanProperty(value);
this.stateChanges.next();
}
private _disabled = false;
#Input()
get value(): MyTel | null {
const {value: {area, exchange, subscriber}} = this.parts;
if (area.length === 3 && exchange.length === 3 && subscriber.length === 4) {
return new MyTel(area, exchange, subscriber);
}
return null;
}
set value(tel: MyTel | null) {
const {area, exchange, subscriber} = tel || new MyTel('', '', '');
this.parts.setValue({area, exchange, subscriber});
this.stateChanges.next();
}
constructor(fb: FormBuilder, private fm: FocusMonitor, private elRef: ElementRef<HTMLElement>) {
this.parts = fb.group({
area: '',
exchange: '',
subscriber: '',
});
fm.monitor(elRef, true).subscribe(origin => {
this.focused = !!origin;
this.stateChanges.next();
});
}
ngOnDestroy() {
this.stateChanges.complete();
this.fm.stopMonitoring(this.elRef);
}
setDescribedByIds(ids: string[]) {
this.describedBy = ids.join(' ');
}
onContainerClick(event: MouseEvent) {
if ((event.target as Element).tagName.toLowerCase() != 'input') {
this.elRef.nativeElement.querySelector('input')!.focus();
}
}
}
example-tel-input-example.html
<div [formGroup]="parts" class="example-tel-input-container">
<input class="example-tel-input-element" formControlName="area" size="3">
<span class="example-tel-input-spacer">–</span>
<input class="example-tel-input-element" formControlName="exchange" size="3">
<span class="example-tel-input-spacer">–</span>
<input class="example-tel-input-element" formControlName="subscriber" size="4">
</div>
But I get the following error:
ERROR Error: mat-form-field must contain a MatFormFieldControl.

Need to import two module and add those in imports and exports section.
import { MatFormFieldModule } from '#angular/material/form-field';
import { MatInputModule } from '#angular/material/input';
#NgModule ({
imports: [ MatFormFieldModule, MatInputModule ],
exports: [ MatFormFieldModule, MatInputModule ]
})
And the most thing which everybody miss this '/' character. if you see the Angular Material Documentation , they also miss this (Last Checked 16 Jun 2020, don't know they even updated or not). I make an example for clarifications
<!-- Wrong -->
<mat-form-field>
<input matInput>
</mat-form-field>
<!-- Right -->
<mat-form-field>
<input matInput />
</mat-form-field>
Look at the snippet carefully. when <input begin it must close with /> but most people miss the / (backslash) character.

Make sure MatInputModule is imported and <mat-form-field> contains <input> with matInput / matSelect directives.
https://github.com/angular/material2/issues/7898

Import MatInputModule, solved my error

You need to specify your class as a provider for MatFormFieldControl
https://material.angular.io/guide/creating-a-custom-form-field-control#providing-our-component-as-a-matformfieldcontrol
#Component({
selector: 'form-field-custom-control-example',
templateUrl: 'form-field-custom-control-example.html',
styleUrls: ['form-field-custom-control-example.css'],
providers: [
{ provide: MatFormFieldControl, useExisting: FormFieldCustomControlExample }
]
})

Also, don't forget to write the name attribute in the input tag:
name="yourName"

if you are using any 'input' tag in your code along with 'mat-form-field', make sure to include 'matInput' in the input tag
if there is any *ngIf present in child tag of 'mat-form-field', specify the *ngIf condition in 'mat-form-field' tag

Another possible issue closing the input tag. If you copy code from one of the Angular examples (https://material.angular.io/components/datepicker/overview), you may end up with the code:
<mat-form-field appearance="fill">
<mat-label>Choose a date</mat-label>
<input matInput [matDatepicker]="picker">
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker #picker></mat-datepicker>
</mat-form-field>
The input should have the close tag (slash):
<input matInput [matDatepicker]="picker" />

This will fix your issue
import {
MatFormFieldModule,
MatInputModule
} from "#angular/material";

Error says that mat-form-field should contain at least one form field from which input is taken.
Ex : matInput mat-select etc.
In your case you may add matInput tag to your input fields within example-tel-input-example.html. And also you could move mat-form-field inside example-tel-input-example component and add it against each matInput field.
<div [formGroup]="parts" class="example-tel-input-container">
<mat-form-field>
<input matInput class="example-tel-input-element" formControlName="area" size="3">
</mat-form-field>
<span class="example-tel-input-spacer">–</span>
<mat-form-field>
<input matInput class="example-tel-input-element" formControlName="exchange" size="3">
</mat-form-field>
<span class="example-tel-input-spacer">–</span>
<mat-form-field>
<input matInput class="example-tel-input-element" formControlName="subscriber" size="4">
</mat-form-field>
</div>
Note : mat-icon or mat-hint cannot be considered as form-fields

Related

Is it possible to show user entered text in <mat-select>?

<mat-select [(ngModel)]="textList" >
<mat-option *ngFor="let textof list" [value]="text">
{{ text }}
</mat-option>
<mat-form-field class="example-full-width">
<input matInput [(ngModel)]="holdReason"/>
</mat-form-field>
</mat-select>
using this code I can show a input field inside the mat-select. but if give some values to that input field that value is not appear in the box. it is empty. Is it possible to just show the text that we entered in input box show inside mat-select
This is what i can see after enter something in the input and just press enter
Here is a working version, you can refer the below stackblitz, do let me know if any doubts. You can enter a new value by giving enter key.
ts
import { ViewChild } from '#angular/core';
import { ElementRef } from '#angular/core';
import { Component } from '#angular/core';
import { MatSelect } from '#angular/material/select';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
#ViewChild('matSelect') matSelect: ElementRef<MatSelect> | MatSelect;
public variables = ['One', 'Two', 'County', 'Three', 'Zebra', 'XiOn'];
public variables2 = [
{ id: 0, name: 'One' },
{ id: 1, name: 'Two' },
];
selected = null;
public filteredList1 = this.variables.slice();
public filteredList2 = this.variables.slice();
public filteredList3 = this.variables.slice();
public filteredList4 = this.variables.slice();
public filteredList5 = this.variables2.slice();
enter(e) {
const matSelect: MatSelect =
this.matSelect && (<ElementRef<MatSelect>>this.matSelect).nativeElement
? <MatSelect>(<ElementRef<MatSelect>>this.matSelect).nativeElement
: <MatSelect>this.matSelect;
// console.log(this.matSelect);
const value = e.target && e.target.value;
if (value && matSelect) {
e.target.value = '';
this.variables.push(value);
this.filteredList1 = this.variables;
this.selected = value;
matSelect.close();
}
}
}
html
<div class="center">
<mat-form-field>
<mat-select placeholder="Basic" #matSelect [(ngModel)]="selected">
<mat-select-filter
[array]="variables"
(filteredReturn)="filteredList1 = $event"
(keydown.enter)="enter($event)"
></mat-select-filter>
<mat-option *ngFor="let item of filteredList1" [value]="item">
{{ item }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
forked stackblitz

Angular: how to programmatically copy a value from one field to another?

Another Angular question... I have the following component that I use in a parent (template-driven) form. (FWIW, I am using PrimeFaces UI components.) When the user clicks the "No" radio button, I would like to autopopulate the mailing address/city/state/ZIP fields from the corresponding fields above. This would be easy in plain JavaScript, but I want to do this in the proper Angular fashion. (I suspect my data binding is WAY improper...) Anyone have any ideas? Thanks in advance for your help!
Screen capture:
Component code:
import { Component, EventEmitter, Input, OnInit, Output } from '#angular/core';
import { DropdownOptions } from 'src/assets/dropdownOptions';
import { ApplicantInformation } from 'src/app/_models/applicantInformation.model';
import { ControlContainer, NgForm } from '#angular/forms';
#Component({
selector: 'app-applicant-information',
templateUrl: './applicant-information.component.html',
styleUrls: ['./applicant-information.component.css'],
viewProviders: [{ provide: ControlContainer, useExisting: NgForm }] // used to link inputs to the parent form
})
export class ApplicantInformationComponent implements OnInit {
name: string = '';
phone = '';
address = '';
city = '';
state = 'AL';
zipCode = '';
mailAddrDifferentFromPhysical: string = 'false';
mailingAddress = '';
mailingCity = '';
mailingState = 'AL';
mailingZIPCode = '';
options: any = new DropdownOptions;
sts: string[] = [];
#Input() ngModel: any = new ApplicantInformation(
this.name,
this.phone,
this.address,
this.city,
this.state,
this.zipCode,
this.mailAddrDifferentFromPhysical,
this.mailingAddress,
this.mailingCity,
this.mailingState,
this.mailingZIPCode,
)
#Output() nameEvent: EventEmitter<any> = new EventEmitter();
onFirstColEntered(name: any) {
this.nameEvent.emit(name);
}
handleRadioClick(str: string) {
this.mailAddrDifferentFromPhysical = str;
}
constructor() {
this.sts = this.options.strAbbrs;
}
ngOnInit(): void {
}
}
Template code (partial):
<label for="address">Address</label>
<input type="text"
pInputText
name="address" id="address"
[ngModel] #address="ngModel"
required [minlength]="8" [ngModelOptions]="{ updateOn: 'blur' }" trim="blur"
placeholder="Address"
(change)="onFirstColEntered(address)">
...
<p class="lg:col-12 md:col-12">
My mailing address is different than the one above.
<p-radioButton
name="mailAddrDifferentFromPhysical" inputId="mailAddrDifferentFromPhysical"
value="true"
label="Yes"
ngModel
(onClick)="handleRadioClick('true');onFirstColEntered(mailAddrDifferentFromPhysical)"></p-radioButton>
<p-radioButton
name="mailAddrDifferentFromPhysical"
value="false"
label="No"
ngModel
(onClick)="handleRadioClick('false');onFirstColEntered(mailAddrDifferentFromPhysical)"></p-radioButton>
</p>
...
<label for="mailingAddress">Mailing Address</label>
<input type="text"
pInputText
name="mailingAddress" id="mailingAddress"
(ngModel)="address?.value" #mailingAddress="ngModel"
required [minlength]="8" [ngModelOptions]="{ updateOn: 'blur' }" trim="blur"
placeholder="Mailing Address"
(change)="onFirstColEntered(mailingAddress)">
You can simply set your mailing values to the above values when the user sets the radion button value to yes i.e. true.
You can use the method that you're already using (onClick method) in the radio button for setting the values.
For example, it should look like this:
handleRadioClick(str: string) {
this.mailAddrDifferentFromPhysical = str;
this.mailingCity = this.city;
this.mailingAddress = this.address
//and so on for the rest of the fields
}
It turns out my data binding (or lack thereof) WAS the issue. I enclosed the ngModel attribute in square brackets on the fields I wanted to copy, then referred to that value in the receiving field, i.e.:
<input type="text"
pInputText
name="mailingAddress" id="mailingAddress"
[ngModel]="address?.value" #mailingAddress="ngModel"
required [minlength]="8" [ngModelOptions]="{ updateOn: 'blur' }" trim="blur"
placeholder="Mailing Address"
(change)="onFirstColEntered(mailingAddress)">

Angular how to wrap input value with double curly braces

What I want to achieve is that when I write inside input field "Foo"
it will become {{Foo}}
First create this directive :
#Directive({
selector: '[format-input]',
})
export class FormatDirective implements DoCheck {
valueIsNull:boolean = true;
constructor(public _elementRef: ElementRef<HTMLInputElement>,
private _renderer: Renderer2) { }
ngDoCheck(): void {
setTimeout(() => {
if(this.valueIsNull){
this.format();
}
}, 150)
fromEvent(this._elementRef.nativeElement, 'blur')
.pipe(
debounceTime(150),
distinctUntilChanged(),
tap(() => {
this.format();
})
)
.subscribe();
}
format(){
this._elementRef.nativeElement.value = "{{ " + this._elementRef.nativeElement.value + " }}"
this.valueIsNull = false;
}
}
Then Import it to your module : e.g app.module :
#NgModule({
declarations: [
FormatDirective
],
imports: [CommonModule],
exports: [
FormatDirective
]
})
export class AppModule { }
Then you can use it anywhere you want :
<input type="text" format-input />
You should use angular templating to achieve this Official Documentation for templating and interpolation and a code sample is given below. this will help you to achieve your usecase.
https://angular.io/guide/interpolation
https://angular.io/api/forms/NgModel
import {Component} from '#angular/core';
import {NgForm} from '#angular/forms';
#Component({
selector: 'example-app',
template: `
<form #f="ngForm" (ngSubmit)="onSubmit(f)" novalidate>
<input name="first" ngModel required #first="ngModel">
<input name="last" ngModel>
<button>Submit</button>
</form>
<p>First name value: {{ first.value }}</p>
<p>First name valid: {{ first.valid }}</p>
<p>Form value: {{ f.value | json }}</p>
<p>Form valid: {{ f.valid }}</p>
`,
})
export class SimpleFormComp {
onSubmit(f: NgForm) {
console.log(f.value); // { first: '', last: '' }
console.log(f.valid); // false
}
}
Thanks
Rigin Oommen

Angular dynamic html at the click of a button

I am creating an HTML form in Angular. I am running into an issue. I want to be able to display a duplicate of an HTML block with a new form control at the click of a button.
Here is what thing look like now:
I would like the user to be able to click the button labeled Click me and have a duplicate of the HTML block display but with a different form control. Do you guys have any suggestions of how I can do that? Here is what I have so far.
import { Component, OnInit, Directive, ViewChild } from '#angular/core';
import { FormControl, FormGroupDirective, NgForm, Validators, FormBuilder, FormGroup } from '#angular/forms';
#Component({
selector: 'app-questions',
templateUrl: './questions.component.html',
styleUrls: ['./questions.component.scss']
})
export class QuestionsComponent implements OnInit {
jobForm: FormGroup = this.fb.group({
companyName: this.fb.control('', [Validators.required ]),
position: this.fb.control('', [Validators.required ]),
description: this.fb.control('', [Validators.required ]),
startDate: this.fb.control('', [Validators.required ]),
endDate: this.fb.control('', [Validators.required ])
});
constructor(private readonly fb: FormBuilder) { }
ngOnInit(): void {
}
displayForm() {
console.log(this.jobForm);
}
}
<h3>Education:</h3>
<form [formGroup]="jobForm">
<mat-form-field >
<mat-label>Company Name: </mat-label>
<input matInput type="text" formControlName="companyName"/>
<mat-error *ngIf="jobForm.controls.companyName.errors">Company name is required</mat-error>
</mat-form-field>
<mat-form-field >
<mat-label>Position: </mat-label>
<input matInput type="text" formControlName="position"/>
<mat-error *ngIf="jobForm.controls.position.errors">Position is required</mat-error>
</mat-form-field>
<mat-form-field >
<mat-label>Select start and end date:</mat-label>
<mat-date-range-input [rangePicker]="picker">
<input matStartDate placeholder="Start date" formControlName="startDate">
<input matEndDate placeholder="End date" formControlName="endDate">
</mat-date-range-input>
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-date-range-picker #picker></mat-date-range-picker>
</mat-form-field>
<mat-form-field >
<mat-label>Description: </mat-label>
<textarea matInput type="text" formControlName="description"></textarea>
<mat-error *ngIf="jobForm.controls.description.errors">Job description is required</mat-error>
</mat-form-field>
</form>
<button (click)="displayForm()">Click me</button>
After a user hits the click me button id like to generate a duplicate form so they can fill out the details.
Thanks
I believe what you're asking for is a way to dynamically add a form group to the page. If that is the case then the solution below should help.
You can use the *ngFor structural directive to iterate over a FormGroup array. The following adjustments will need to be made:
import { Component, OnInit, Directive, ViewChild } from '#angular/core';
import { FormControl, FormGroupDirective, NgForm, Validators, FormBuilder, FormGroup } from '#angular/forms';
#Component({
selector: 'app-questions',
templateUrl: './questions.component.html',
styleUrls: ['./questions.component.scss']
})
export class QuestionsComponent implements OnInit {
jobForms: FormGroup[] = []; // Declare an empty array
constructor(private readonly fb: FormBuilder) { }
ngOnInit(): void {
this.addFormRow(); // Add an empty form group to the array
}
//displayForm() {
// console.log(this.jobForm);
//}
// Add an additional row to the jobForms array - to be called from the template
addFormRow() {
this.jobForms.push(this.fb.group({
companyName: this.fb.control('', [Validators.required ]),
position: this.fb.control('', [Validators.required ]),
description: this.fb.control('', [Validators.required ]),
startDate: this.fb.control('', [Validators.required ]),
endDate: this.fb.control('', [Validators.required ])
}));
}
}
<h3>Education:</h3>
<form *ngFor="let formGroup of jobForms"
[formGroup]="formGroup">
<mat-form-field >
<mat-label>Company Name: </mat-label>
<input matInput type="text" formControlName="companyName"/>
<mat-error *ngIf="jobForm.controls.companyName.errors">Company name is required</mat-error>
</mat-form-field>
<mat-form-field >
<mat-label>Position: </mat-label>
<input matInput type="text" formControlName="position"/>
<mat-error *ngIf="jobForm.controls.position.errors">Position is required</mat-error>
</mat-form-field>
<mat-form-field >
<mat-label>Select start and end date:</mat-label>
<mat-date-range-input [rangePicker]="picker">
<input matStartDate placeholder="Start date" formControlName="startDate">
<input matEndDate placeholder="End date" formControlName="endDate">
</mat-date-range-input>
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-date-range-picker #picker></mat-date-range-picker>
</mat-form-field>
<mat-form-field >
<mat-label>Description: </mat-label>
<textarea matInput type="text" formControlName="description"></textarea>
<mat-error *ngIf="jobForm.controls.description.errors">Job description is required</mat-error>
</mat-form-field>
</form>
<!-- Call addFormRow() to add a FormGroup to the array -->
<button (click)="addFormRow()">Click me</button>
If you can use Lodash library it would be easy
//const newjobFormGroup = _.cloneDeep(jobForm) as FormGroup;
CopyJobForm(toCopyForm: FormGroup){
//return _.cloneDeep(jobForm) as FormGroup;
return _.cloneDeep(FormGroup) as FormGroup;
}
Or
this answer for a full deep clone
/**
* Deep clones the given AbstractControl, preserving values, validators, async validators, and disabled status.
* #param control AbstractControl
* #returns AbstractControl
*/
export function cloneAbstractControl<T extends AbstractControl>(control: T): T {
let newControl: T;
if (control instanceof FormGroup) {
const formGroup = new FormGroup({}, control.validator, control.asyncValidator);
const controls = control.controls;
Object.keys(controls).forEach(key => {
formGroup.addControl(key, cloneAbstractControl(controls[key]));
})
newControl = formGroup as any;
}
else if (control instanceof FormArray) {
const formArray = new FormArray([], control.validator, control.asyncValidator);
control.controls.forEach(formControl => formArray.push(cloneAbstractControl(formControl)))
newControl = formArray as any;
}
else if (control instanceof FormControl) {
newControl = new FormControl(control.value, control.validator, control.asyncValidator) as any;
}
else {
throw new Error('Error: unexpected control value');
}
if (control.disabled) newControl.disable({emitEvent: false});
return newControl;
}

How to check for state change in angular 4/6?

My task is to create an account information web page which consists of 4 pre-filled fields (given name, family name, username and email) and a common save button at the bottom. User can change any field by the respective field. I want save button to be enabled only if user changes any fields. Any method to track state changes? My code is as follows:
<mat-card-content>
<div class="form-group">
<mat-form-field class="simple-form-field-50">
<input matInput placeholder="Given name" name="givenName" formControlName="givenName">
</mat-form-field>
<mat-form-field class="simple-form-field-50">
<input matInput placeholder="Family name" name="familyName" formControlName="familyName">
</mat-form-field>
<br>
<mat-form-field>
<input matInput placeholder="Email" name="email" formControlName="email">
</mat-form-field>
<br>
<button
[disabled]="waiting"
class="simple-form-button"
color="primary"
mat-raised-button
type="submit"
value="submit">
Save
</button>
</div>
</mat-card-content>
My Code Output:
Since you're using a Reactive Form, you can use valueChanges on the FormGroup.
Since it is of type Observable, you can subscribe to it to set a variable of type boolean that will be used in the template to enable the button.
...
#Component({...})
export class AppComponent {
form: FormGroup;
disableButton = true;
ngOnInit() {
...
this.form.valueChanges.subscribe(changes => this.disableButton = false);
}
}
And in your template:
<form [formGroup]="form">
...
<button [disabled]="disableButton">Submit</button>
</form>
UPDATE:
If you want to disable it when values don't really change, check for the current value of the form with the previous value:
import { Component } from '#angular/core';
import { FormGroup, FormControl } from '#angular/forms';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
form: FormGroup;
disableButton = true;
userValue = {
firstName: 'John',
lastName: 'Doe',
email: 'john.doe#domain.com'
}
ngOnInit() {
this.form = new FormGroup({
firstName: new FormControl(),
lastName: new FormControl(),
email: new FormControl()
});
this.form.patchValue(this.userValue);
this.form.valueChanges.subscribe(changes => this.wasFormChanged(changes));
}
private wasFormChanged(currentValue) {
const fields = ['firstName', 'lastName', 'email'];
for(let i = 0; i < fields.length; i++) {
const fieldName = fields[i];
if(this.userValue[fieldName] !== currentValue[fieldName]) {
console.log('Came inside');
this.disableButton = false;
return;
}
}
this.disableButton = true;
}
}
NOTE: StackBlitz is updated accordingly.
Here's a Working Sample StackBlitz for your ref.
onChange(targetValue : string ){
console.log(targetValue );}
<input matInput placeholder="test" name="test" formControlName="testNM" (input)="onChange($event.target.value)">
This is called Dirty Check.
You may find this SO answer very useful:
https://stackoverflow.com/a/50387044/1331040
Here is the guide for Template-Driven Forms
https://angular.io/guide/forms
Here is the guide for Reactive Forms
https://angular.io/guide/reactive-forms
And here is the difference between two concepts
https://blog.angular-university.io/introduction-to-angular-2-forms-template-driven-vs-model-driven/
Hope these help.
I would do something like this:
form: FormGroup;
disableButton = true;
originalObj: any;
ngOnInit() {
this.form = new FormGroup({
control: new FormControl('Value')
});
this.originalObj = this.form.controls['control'].value; // store the original value in one variable
this.form.valueChanges.subscribe(changes => {
if (this.originalObj == changes.control) // this if added for check the same value
{
this.disableButton = true;
}
else {
this.disableButton = false;
}
}
);
}
WORKING EXAMPLE

Categories