Expression has changed after it was checked. Previous value: 'mat-focused: false'. Current value: 'mat-focused: true'. in angular 8? - angular8

html code:
ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'mat-focused: false'. Current value: 'mat-focused: true'.
When I click packmaterial input it has given this error.
<div formArrayName="packageArray" *ngFor="let item of packageArray.controls; let i = index;">
<div [formGroupName]="i" class="add-div" >
<p>Level {{i+1}} Pack</p>
<div class="d-flex justify-content-between">
<mat-form-field>
<input matInput type="text" (click)="addLevelPack(i)" placeholder="Package Material" formControlName="packMaterial" required>
In this line, I have got this Error
</mat-form-field>
<mat-form-field>
<input matInput type="text" placeholder="UOM" formControlName="UOM" required>
</mat-form-field>
<mat-form-field>
<input matInput type="text" placeholder="Quantity" formControlName="Quantity" required>
</mat-form-field>
<mat-form-field>
<input matInput type="text" placeholder="Weight(kgs)" formControlName="weight" required>
</mat-form-field>
</div>
</div>
</div>
<div class="btn-custom" (click)="addPackage()">
<span mat-raised-button style="cursor:pointer">Add packaging +</span>
</div>
<p>Total packaging</p>
<div *ngFor="let item of packList; let i = index;">
<div class="file-name ">
<div class="d-flex">
<div class="p-2">
<div class="add-div d-flex justify-content-between">
<div> Level {{i+1}} Pack </div>
<div>{{item.packMaterial}}</div>
<div>{{item.UOM}}</div>
<div>{{item.Quantity}}</div>
<div>{{item.weight}}</div>
</div>
</div>
<div class="ml-auto p-2">(i need this arrangement also)
<mat-checkbox>WHD</mat-checkbox>
</div>
</div>
</div>
</div>
``````````````````````````````````````````````````````
component.ts(ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'mat-focused: false'. Current value: 'mat-focused: true')
````````````````````````````````````````````````````````
ngOnInit() {
this.packageArray = this.formulationForm.get('packageArray') as FormArray;
this.addPackage();
}
addPackage(){
this.packageArray.push(this.createPackage());
}
createPackage():FormGroup{
return this.formBuilder.group({
packMaterial : new FormControl(null, Validators.required),
UOM : new FormControl(null, Validators.required),
Quantity: new FormControl(null, Validators.required),
weight: new FormControl(null, Validators.required)
});
}
addLevelPack(index){
this.dialog.open(SelectMaterialComponent, {data :{matList: this.packList , type: "Packaging"}, minWidth: '60vw', minHeight: '40vh'})
.afterClosed().subscribe( response => {
if(!!response) {
console.log(response);
this.formulationForm.get("packageArray").value.splice(-1, 1);
this.formulationForm.patchValue({packageArray : [
...this.formulationForm.get("packageArray").value,
{
packMaterial: response[0].title,
UOM: response[0].uom,
Quantity: 1,
weight: response[0].wt_in_kgs_per_unit
}
]});
this.packList = this.formulationForm.get("packageArray").value;
}
})
}

Try adding restoreFocus:false in your dialog configuration like this:
this.dialog.open(SelectMaterialComponent, {
restoreFocus:false, // <-- Line to add
data :{matList: this.pack....
... }
})

Related

Vue v-model/v-for doesn't update on mount, but after first manual change

I have a dropdown list "functions" that is filled with database entries and a dropdown list with 2 hardcoded entries. When the vue website is opened the dropdown list remains empty but as soon as I change the value of the other dropdown field the desired data from the database is available.
I'm a bit confused because I expected that adding "retrieveFunctions()" into the mounted() function would trigger the v-for, and even more confused that changing something in another select field suddenly triggers it.
The HTML code:
<template>
<div class="submit-form">
<div v-if="!submitted">
<div class="row">
<div class="col-sm-12">
<p><a style="width:500px" class="btn btn-info" data-toggle="collapse" href="#generalInformation" role="button" aria-expanded="true" >
General Information</a></p>
<div class="collaps show" id="generalInformation">
<!-- NAME -->
<div class="form-group">
<input placeholder="Name" type="text" class="form-control"
id="name" required v-model="component.name" name="name">
</div>
<!-- DOMAIN -->
<div class="input-group mb-3">
<div class="input-group-prepend">
<label style="width:100px" class="input-group-text" for="inputGroupDomain">Domain</label>
</div>
<select v-model="component.domain"
class="custom-select"
id="inputGroupDomain"
>
<option value="Power System">Power System</option>
<option value="ICT">ICT</option>
</select>
</div>
<!-- FUNCTION -->
<div class="input-group mb-3">
<div class="input-group-prepend">
<label style="width:100px" class="input-group-text" for="inputGroupFunction">Functions</label>
</div>
<select v-model="_function" class="custom-select" id="inputGroupFunction">
<option :class="{ active: index == currentIndex }"
v-for="(_function, index) in functions"
:key="index"
value= _function.name>
{{ _function.name }}
</option>
</select>
</div>
</div>
<p>
<button #click="saveComponent" class="btn btn-success">Add Component</button>
</p>
</div>
</div>
</div>
<div v-else>
<h4>Component was added succesfully!</h4>
<button class="btn btn-success" #click="newComponent">Proceed</button>
</div>
The script part:
<script>
import FunctionDataService from "../services/FunctionDataService";
export default {
name: "add-component",
data() {
return {
component: {
id: null,
name: "",
type: "",
domain: "",
},
submitted: false
};
},
methods: {
retrieveFunctions() {
FunctionDataService.getAll()
.then(response => {
this.functions = response.data;
console.log(response.data);
})
.catch(e => {
console.log(e);
});
},
refreshList() {
this.retrieveFunctions();
},
},
mounted() {
this.retrieveFunctions();
}
};
</script>
refreshList() {
this.retrieveFunctions();
},
},
mounted() {
this.retrieveFunctions();
}
};
</script>
State in the beginning: Dropdown list empty
State after selecting something in the upper dropdown list: Database entries are visible and correct
You need to initiate all responsive properties on the data return object with either a value (empty string, array, object, etc) or null. Currently it's missing the _function attribute used in the select v-model and the functions array used in the v-for. You can try to change the data to the following:
data() {
return {
_function: "",
functions: [],
component: {
id: null,
name: "",
type: "",
domain: "",
},
submitted: false
};
},

validate form inputs bootstrap4

I have this code in my vue template
<div class="form-row" :class="{'was-validated': this.checkPassword()}">
<div class="col-6">
<label>Password</label>
<input :type="showPassword ? 'text' : 'password'" class="form-control" ref="password" required v-model="password">
<div class="valid-feedback" v-if="!error">
Password match
</div>
<div class="invalid-feedback" v-else>
Password not match
</div>
</div>
<div class="col-6">
<label>Confirm password</label>
<div class="input-group">
<input :type="showPassword ? 'text' : 'password'" class="form-control" ref="passwordCheck" required v-model="passwordCheck" #change="checkPassword()">
<div class="input-group-append">
<button class="btn btn-secondary" #click.prevent="copyToClipboard()"><i class="fas fa-clipboard"></i></button>
</div>
</div>
</div>
</div>
I want to show like the bootstrap4 documentation a green input field if the password matches or a red one if the password aren't matching. I'm trying by adding the was-validated class to the form-row if the demanded method return true but when the view where the password inputs are rendered the two input fields are always red. How I can fix this to give the correct feedback to the user?
Please always share all the relevant parts of the component otherwise, it's hard to tell where the problem resides. Here, you haven't shared your <script> section. Anyway, I guess this should put you on the right track.
<template>
<div class="form-row" :class="{'was-validated': this.checkPassword()}">
<div class="col-6">
<label>Password</label>
<label>
<input :type="showPassword ? 'text' : 'password'" class="form-control" :class="getPasswordClass()"
ref="password" required v-model="password">
</label>
</div>
<div class="col-6">
<label>Confirm password</label>
<div class="input-group">
<label>
<input :type="showPassword ? 'text' : 'password'" class="form-control" :class="getPasswordClass()"
ref="passwordCheck" required v-model="passwordCheck" #input="checkPassword()">
</label>
<div class="input-group-append">
<button class="btn btn-secondary" #click.prevent="copyToClipboard()"><i
class="fas fa-clipboard"></i></button>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
password: null,
passwordCheck: null,
error: true,
showPassword: true,
}
},
methods: {
checkPassword() {
this.error = this.password !== this.passwordCheck;
},
getPasswordClass() {
if (!this.password || !this.passwordCheck) {
return '';
}
return this.error ? 'is-invalid' : 'is-valid'
},
copyToClipboard() {
//
}
}
}
</script>
So, in my opinion, you should only set the dynamic class (is-valid or is-invalid) when both inputs are provided. In this example I've added that to both password and passwordCheck fields but I think it's enough to just apply it to the passwordCheck because that's the one checked against the password.
If you only want to check after user leaves the field you could adjust the code like this:
In the template remove:
:class="{'was-validated': this.checkPassword()}"
And update:
#blur="checkPassword()
In the data() add:
blurred: false,
In the methods update:
methods: {
checkPassword() {
this.blurred = true;
this.error = this.password !== this.passwordCheck;
},
getPasswordClass() {
if (!this.blurred) {
return '';
}
return this.error ? 'is-invalid' : 'is-valid'
},
...
}

Angular prefilled form data becomes null when submitting

I have created an Angular form to update the user details. The fields values of the form are filled by the user details fetched from the backend when the form loads. If the user wishes to update any field they can update and submit the form. But the field values of the fields which user didn't change are set as null even though those fields are initialized at the beginning. Can someone please explain how to get the prefilled unchanged field values when submitting the form?
The HTML file is this,
<app-navbar></app-navbar>
<div class="container">
<form [formGroup]="profileForm" style="margin-top: 60px;" disabled="true" (ngSubmit)="onSubmit()">
<input type="file" id="file" (change)="onFileSelected($event)" accept="image\jpeg" formControlName="profPic">
<div class="row">
<!--Profile Picture-->
<div class="col-12 col-md-4 d-flex justify-content-center">
<label for="file">
<a (mouseenter)="hoverIdx = 1"
(mouseleave)="hoverIdx = -1"
id="overlay">
<span [ngClass]="{ 'overlay-icon': true, 'hide': hoverIdx !== 1 }"
class="rounded-circle">
<fa-icon [icon]="cameraIcon" class="icon"></fa-icon>
</span>
<img
[src]="profPic"
class="rounded-circle"
width="300"
height="300"
/>
</a>
</label>
<div class="col-md-2 align-self-end ml-auto p-2" id="deleteIcon">
<fa-icon [icon]="deleteIcon"></fa-icon>
</div>
</div>
<div class="col-12 col-md-8">
<div class="card" style="margin-bottom: 20px;">
<div class="card-body" >
<!---Intro-->
<div class="row" style="font-size: 60px;">
<div class="col-12">Hi, {{ fNme }}</div>
</div>
<!--first name & last name-->
<div class="row" style="margin-top: 10px;">
<div class="col-12 col-md-6">
<mat-form-field appearance="outline">
<input formControlName="fName"
matInput placeholder="First Name"
[value]="fNme"
(change)="fNmeChnge = true"/>
</mat-form-field>
</div>
<div class="col-12 col-md-6">
<mat-form-field appearance="outline">
<input formControlName="lName"
matInput placeholder="Last Name"
[value]="lNme"
(change)="lNmeChnge = true" />
</mat-form-field>
</div>
</div>
<!--row-->
<!-- email & country-->
<div class="row" style="margin-bottom: 25px;">
<div class="col-12 col-md-6">
<mat-form-field appearance="outline">
<input formControlName="email"
matInput placeholder="Email"
[value]="email"
(change)="emailChnge = true"/>
</mat-form-field>
</div>
<div class="col-12 col-md-6">
<mat-form-field appearance="outline" >
<input formControlName="country"
matInput placeholder="Country"
[value]="country"
(change)="countryChnge = true"/>
</mat-form-field>
</div>
</div>
<!--row-->
</div>
</div>
<button type="button" class="btn btn-primary float-right" style="margin-left:10px" type="submit">Save</button>
<button type="button" class="btn btn-outline-primary float-right" (click)="cancel()">Cancel</button>
</div><!--col-md-8-->
</div><!--row-->
</form>
</div><!--container-->
The component file is this,
import { User } from './../shared/user.model';
import { F_NAME, L_NAME, AUTHENTICATED_USER, PROF_PIC, BASE64URL } from './../../app.constants';
import { Component, OnInit, Inject } from '#angular/core';
import { FormGroup, FormControl, Validators } from '#angular/forms';
import { AuthenticationService } from '../service/authentication.service';
import { MAT_DIALOG_DATA, MatDialogRef, MatDialog } from '#angular/material/dialog';
import { DialogOverviewExampleDialog } from './dialog';
import { faCamera, faTrashAlt } from '#fortawesome/free-solid-svg-icons';
import { DomSanitizer } from '#angular/platform-browser';
#Component({
selector: 'app-profile',
templateUrl: './profile.component.html',
styleUrls: ['./profile.component.css']
})
export class ProfileComponent implements OnInit {
user: User;
cameraIcon = faCamera;
deleteIcon = faTrashAlt;
profPic: any;
profileForm: FormGroup;
email: string;
fNme: string;
lNme: string;
country: any;
selectedFile: File = null;
base64Data: any;
fNmeChnge: any;
lNmeChnge: any;
countryChnge: any;
emailChnge: any;
title = 'Profile';
constructor(
private service: AuthenticationService,
public dialog: MatDialog,
private sanitizer: DomSanitizer
) {
}
ngOnInit() {
this.email = sessionStorage.getItem(AUTHENTICATED_USER);
this.profileForm = new FormGroup({
fName: new FormControl(null, [Validators.required]),
lName: new FormControl(null, Validators.required),
email: new FormControl(null, [Validators.required, Validators.email]),
country: new FormControl(null, Validators.required)
});
this.service.getUser(this.email)
.subscribe(res => {
this.fNme = res.fNme;
this.lNme = res.lNme;
this.country = res.country;
this.profPic = BASE64URL + res.profPic ;
});
}
openDialog(): void {
const dialogRef = this.dialog.open(DialogOverviewExampleDialog, {
width: '500px'
});
}
onFileSelected(event){
this.selectedFile = event.target.files[0] as File;
const reader = new FileReader();
reader.onload = e => this.profPic = reader.result;
reader.readAsDataURL(this.selectedFile);
}
onSubmit() {
const fd = new FormData();
fd.append('file', this.selectedFile);
this.service.uploadImage(fd, this.email);
this.user = new User(this.profileForm.get('fName').value,
this.profileForm.get('lName').value,
this.profileForm.get('country').value,
this.profileForm.get('email').value);
console.log(this.user);
this.service.updateProfile(this.user, this.email);
// .subscribe(res => {
// this.fNme = res.fNme;
// this.lNme = res.lNme;
// this.country = res.country;
// this.profPic = BASE64URL + res.profPic ;
// });
this.ngOnInit();
}
I gets the user data from the server via these codes,
uploadImage(file: FormData, email: string) {
this.http.put<any>(`${API_URL}/profile-picture/${email}`, file)
.subscribe(res => {console.log(res); });
}
updateProfile(user: User, email: string) {
this.http.put<any>(`${API_URL}/profile/${email}`, user).subscribe();
}
getUser(email: string) {
return this.http.get<any>(`${API_URL}/user/${email}`);
}

Why my vuejs wallpaper calculator doesn't work?

After changing the numbers, for example, in the first or seconde input, the result is false. Only changing the values in gives me the right results.
If I put 40 in the first input and 3 in the seconde one and others I leave the same, the result should be 26.
Please, could you help me.
<body>
<div id="app">
<h1>{{title}}</h1>
<form v-on:submit.prevent>
<span>Довжина стіни, м:</span><br>
<input class="length" type="text" name="length" v-model.text.trim="wall_length"><br>
<span>Висота стіни, м:</span><br>
<input class="heigth" type="text" name="heigth" v-model.text.trim="wall_height"><br>
<hr>
<span>Ширина рулона, м:</span><br>
<select v-model="selected">
<option v-for="key in weight" :value="key">{{key}}</option>
</select><br>
<span>Довжина рулона, м:</span><br>
<input class="length_roll" type="text" name="length_roll" v-model.text.trim="length" maxlength="5"><br>
<span>Повтор малюнка (рапорт), см:</span><br>
<input class="rapport" type="text" name="rapport" v-model.text.trim="rapport"><br><br>
<input type="submit" value="Порахувати" v-on:click="calc">
</form>
<span>{{result}} рулонів шпалер</span>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script>
new Vue({
el : "#app",
data: {
title: "Калькулятор шпалер",
wall_length: 20,
wall_height: 2.75,
weight: [0.53, 1.05],
rapport: 0,
length: 10.05,
selected: 0.53,
polotno_for_room: 0,
polotno_rulon: 0,
result: 0
},
methods: {
calc: function () {
this.polotno_for_room = (this.wall_length + this.wall_height)/ this.selected;
this.polotno_rulon = this.length /(this.wall_height + 0.10);
this.result = Math.ceil(this.polotno_for_room/this.polotno_rulon);
console.log((this.wall_length + this.wall_height)/ this.selected);
console.log(this.polotno_rulon = this.length /(this.wall_height + 0.10));
console.log(Math.ceil(this.polotno_for_room/this.polotno_rulon));
}
}
});
</script>
</body>
Your main problem is that you are using an input with type="text". The result of this is a string. When you start your application, the state of your component is initialised to what you set as data, which makes wall_length and wall_height numbers. The moment you change one of the inputs, the type of these variables changes to a `string.
Due to how javascript works, it will now do string concatenation instead of adding two numbers. It will then convert it back to a number for dividing by whatever this.selected is. The result is that instead of doing dividing 40 + 3 = 43 by this.selected, you are dividing "40" + 3 = 403 by this.selected. Notice the typeof checks I added behind the inputs to showcase this.
new Vue({
el: "#app",
data: {
title: "Калькулятор шпалер",
wall_length: 40,
wall_height: 3,
weight: [0.53, 1.05],
rapport: 0,
length: 10.05,
selected: 0.53,
polotno_for_room: 0,
polotno_rulon: 0,
result: 0
},
methods: {
calc: function() {
this.polotno_for_room = (this.wall_length + this.wall_height) / this.selected;
this.polotno_rulon = this.length / (this.wall_height + 0.10);
this.result = Math.ceil(this.polotno_for_room / this.polotno_rulon);
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<h1>{{title}}</h1>
<form v-on:submit.prevent>
<span>Довжина стіни, м:</span><br>
<input class="length" type="text" name="length" v-model.text.trim="wall_length"> {{ typeof wall_length }}<br>
<span>Висота стіни, м:</span><br>
<input class="heigth" type="text" name="heigth" v-model.text.trim="wall_height"> {{ typeof wall_height }}<br>
<hr>
<span>Ширина рулона, м:</span><br>
<select v-model="selected">
<option v-for="key in weight" :value="key">{{key}}</option>
</select><br>
<span>Довжина рулона, м:</span><br>
<input class="length_roll" type="text" name="length_roll" v-model.text.trim="length" maxlength="5"><br>
<span>Повтор малюнка (рапорт), см:</span><br>
<input class="rapport" type="text" name="rapport" v-model.text.trim="rapport"><br><br>
<input type="submit" value="Порахувати" v-on:click="calc">
</form>
<span>{{result}} рулонів шпалер</span>
</div>
One of your options is to use parseFloat(..) liberally. It will make sure you are using only numbers in your calculation.
new Vue({
el: "#app",
data: {
title: "Калькулятор шпалер",
wall_length: 40,
wall_height: 3,
weight: [0.53, 1.05],
rapport: 0,
length: 10.05,
selected: 0.53,
polotno_for_room: 0,
polotno_rulon: 0,
result: 0
},
methods: {
calc: function() {
this.polotno_for_room = (parseFloat(this.wall_length) + parseFloat(this.wall_height)) / parseFloat(this.selected);
this.polotno_rulon = parseFloat(this.length) / (parseFloat(this.wall_height) + 0.10);
this.result = Math.ceil(parseFloat(this.polotno_for_room) / parseFloat(this.polotno_rulon));
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<h1>{{title}}</h1>
<form v-on:submit.prevent>
<span>Довжина стіни, м:</span><br>
<input class="length" type="text" name="length" v-model.text.trim="wall_length"><br>
<span>Висота стіни, м:</span><br>
<input class="heigth" type="text" name="heigth" v-model.text.trim="wall_height"><br>
<hr>
<span>Ширина рулона, м:</span><br>
<select v-model="selected">
<option v-for="key in weight" :value="key">{{key}}</option>
</select><br>
<span>Довжина рулона, м:</span><br>
<input class="length_roll" type="text" name="length_roll" v-model.text.trim="length" maxlength="5"><br>
<span>Повтор малюнка (рапорт), см:</span><br>
<input class="rapport" type="text" name="rapport" v-model.text.trim="rapport"><br><br>
<input type="submit" value="Порахувати" v-on:click="calc">
</form>
<span>{{result}} рулонів шпалер</span>
</div>

Angular2: How to enable save button if any model value changed on edit page

I am new for angular 2. I have a page where we can edit details of customer profile. How to enable save button if any property of has been changed. I know it is possible in angular1 by using $watch.
It is simple. dirty check your form if you are using #angular/forms.
create form
export class HeroDetailComponent4 {
heroForm: FormGroup;
states = states;
constructor(private fb: FormBuilder) {
this.createForm();
}
createForm() {
this.heroForm = this.fb.group({
name: ['', Validators.required ],
street: '',
city: '',
state: '',
zip: '',
power: '',
sidekick: ''
});
}
}
HTML:
<h2>Hero Detail</h2>
<h3><i>A FormGroup with multiple FormControls</i></h3>
<form [formGroup]="heroForm" novalidate>
<button (click)="submit()" [disabled]="!heroForm.dirty" type="button">Submit</button>
<div class="form-group">
<label class="center-block">Name:
<input class="form-control" formControlName="name">
</label>
</div>
<div class="form-group">
<label class="center-block">Street:
<input class="form-control" formControlName="street">
</label>
</div>
<div class="form-group">
<label class="center-block">City:
<input class="form-control" formControlName="city">
</label>
</div>
<div class="form-group">
<label class="center-block">State:
<select class="form-control" formControlName="state">
<option *ngFor="let state of states" [value]="state">{{state}}</option>
</select>
</label>
</div>
<div class="form-group">
<label class="center-block">Zip Code:
<input class="form-control" formControlName="zip">
</label>
</div>
<div class="form-group radio">
<h4>Super power:</h4>
<label class="center-block"><input type="radio" formControlName="power" value="flight">Flight</label>
<label class="center-block"><input type="radio" formControlName="power" value="x-ray vision">X-ray vision</label>
<label class="center-block"><input type="radio" formControlName="power" value="strength">Strength</label>
</div>
<div class="checkbox">
<label class="center-block">
<input type="checkbox" formControlName="sidekick">I have a sidekick.
</label>
</div>
</form>
use heroForm.dirty to check whether form data is changed. it will set to true if any control inside heroForm has been changed.
<button (click)="submit()" [disabled]="!heroForm.dirty" type="button">Submit</button>
Refer angular docs for more info
you can use form control validation for it.
some thing like this in html template:
<form fxLayout="column" [formGroup]="form">
<mat-form-field class="mb-1">
<input matInput [(ngModel)]="userProfileChangeModel.firstName" placeholder="نام"
[formControl]="form1.controls['fname']">
<small *ngIf="form1.controls['fname'].hasError('required') && form1.controls['fname'].touched"
class="mat-text-warn">لطفا نام را وارد نمایید.
</small>
<small *ngIf="form1.controls['fname'].hasError('minlength') && form1.controls['fname'].touched"
class="mat-text-warn">نام باید حداقل 2 کاراکتر باشد.
</small>
<small *ngIf="form1.controls['fname'].hasError('pattern') && form1.controls['fname'].touched"
class="mat-text-warn">لطفا از حروف فارسی استفاده نمائید.
</small>
</mat-form-field>
<mat-card-actions>
<button mat-raised-button (click)="editUser()" color="primary" [disabled]="!form1.valid" type="submit">
ذخیره
</button>
</mat-card-actions>
</form>
and like this in ts file:
this.form = this.bf.group({
fname: [null, Validators.compose([
Validators.required,
Validators.minLength(2),
Validators.maxLength(20),
Validators.pattern('^[\u0600-\u06FF, \u0590-\u05FF]*$')])],
});
if:
[disabled]="!form1.valid"
is valid save button will be active
bast regards.
You can use disabled option like below :
<button [disabled]="isInvalid()" type="button" (click) = "searchClick()" class="button is-info">
<span class="icon is-small">
<i class="fa fa-search" aria-hidden="true"></i>
</span>
<span>Search</span>
</button>
you can create isInvalid() in your ts file and check if that property is empty or not and return that boolean value
and for hide button on a state you can use *ngIf in line directive.
This worked for me, pls try.
In your html,
<input type="text" [ngModel]="name" (ngModelChange)="changeVal()" >
<input type="text" [ngModel]="address" (ngModelChange)="changeVal()" >
<input type="text" [ngModel]="postcode" (ngModelChange)="changeVal()" >
<button [disabled]="noChangeYet" (click)="clicked()" >
<span>SUBMIT</span>
</button>
In your component
export class customer implements OnInit {
name: string;
address: string;
postcode: string;
noChangeYet:boolean = true;
constructor() {}
changeVal(){ // triggers on change of any field(s)
this.noChangeYet = false;
}
clicked(){
// your function data after click (if any)
}
}
Hope this is what you need.
Finally I resolved this issue.
import { Component, Input, Output, OnInit, AfterViewInit, EventEmitter, ViewChild } from '#angular/core';
#Component({
selector: 'subscribe-modification',
templateUrl: './subscribe.component.html'
})
export class SampleModifyComponent implements OnInit, AfterViewInit {
disableSaveSampleButton: boolean = true;
#ViewChild('sampleModifyForm') sampleForm;
ngAfterViewInit() {
setTimeout(() => {
this.sampleForm.control.valueChanges.subscribe(values => this.enableSaveSampleButton());
}, 1000);
}
enableSaveSampleButton() {
console.log('change');
this.disableSaveSampleButton = false;
}
}
HTML
<button id="btnSave" class="btn btn-primary" (click)="save()" />