I'm a beginner angular2 programmer and studying it now.
I'm creating a form that when user clicks a employee, it shows editable form with employee's current data. But, when I click a user first time (even click the same user again), user's information doesn't come up to input value.
<!-- User list part-->
<table>
<tr *ngFor="let emp of employees" (click)="empBtn(emp.empId)">
<td>{{ emp.empName }}</td>
<td>{{ getDepartName(emp.departId) }}</td>
<td>{{ emp.empPhone }}</td>
<td>{{ emp.wages.wage }}</td>
</tr>
</table>
<!-- Editable part -->
<button (click)="addBtn()">Add</button>
<div *ngIf="modeAdd || modeEdit">
<form #form ="ngForm" (ngSubmit) = "onSubmit(form.value)">
<label>Name </label><input type="text" name="name" value="{{ eName }}" ngModel>
<label>Department </label><select name="depart" value="{{ eDepartment }}" ngModel><option *ngFor="let depart of departments">{{ depart.departName }}</option></select>
<label>Phone </label><input type="text" value="{{ ePhone }}" name="phone" ngModel>
<label>Wage </label><input type="text" value="{{ eWage }}" name="wage" ngModel>
<button type="submit">Submit</button>
</form>
</div>
But, If I click another user, it shows values inside form's input tags. I was able to solve this with setting eName, eDepartment, ePhone, eWage as two-way binding with like [(ngModule)]="eName", but I don't know why my code doesn't work correctly.
This is typescript part. empBtn is called when user click a user and it sets eName, eDepartment, ePhone, eWage. FYI, even though I declare default value on eName, eDepartment, ... it doesn't come up as well. Thank you for your consideration.
eName: string;
eDepartment: string;
ePhone: string;
eWage: number;
empBtn(empId: number): void {
console.log('click Employee ID: ', empId);
this.getEmployee(empId);
this.modeAdd = false;
this.modeEdit = true;
}
getEmployee(employeeId: number){
let selectedEmp: Employee = this.employeesObj.getEmployee(employeeId);
if(!selectedEmp){
console.log("employees: Invalid Employee ID");
}else{
console.log("employees: Get Employee info",selectedEmp.empName);
this.eName = selectedEmp.empName;
this.eDepartment = this.getDepartName(selectedEmp.departId);
this.ePhone = selectedEmp.empPhone;
this.eWage = selectedEmp.wages.wage;
}
}
I suggest you to study reactive form but with this problem.
http://blog.thoughtram.io/angular/2016/06/22/model-driven-forms-in-angular-2.html
HTML
<form [formGroup]="form" (ngSubmit) = "onSubmit(form.value)">
<label>Name </label>
<input type="text" formControlName="eName">
<label>Department </label>
<select formControlName="eDepartment">
<option *ngFor="let depart of departments">{{ depart.departName }}</option>
</select>
<label>Phone </label>
<input type="text" formControlName="ePhone">
<label>Wage </label>
<input type="text" formControlName="eWage">
<button type="submit">Submit</button>
</form>
importing modules
import { Component, OnInit} from '#angular/core';
import { FormGroup, FormControl, Validators, FormBuilder } from '#angular/forms';
On your component
form: FormGroup; // declare form as formgroup
eName: string;
eDepartment: string;
ePhone: string;
eWage: number;
constructor(private fb: FormBuilder){ }
ngOnInit() {
this.updateForm()
}
updateForm(): void {
this.form = this.fb.group({
eName: [this.eName, Validators.required],
eDepartment: [this.eDepartment, Validators.required],
ePhone: [this.ePhone, Validators.required],
eWage: [this.eWage, Validators.required],
})
}
empBtn(empId: number): void {
console.log('click Employee ID: ', empId);
this.getEmployee(empId);
this.modeAdd = false;
this.modeEdit = true;
this.updateForm();
}
getEmployee(employeeId: number){
let selectedEmp: Employee = this.employeesObj.getEmployee(employeeId);
if(!selectedEmp){
console.log("employees: Invalid Employee ID");
}else{
console.log("employees: Get Employee info",selectedEmp.empName);
this.eName = selectedEmp.empName;
this.eDepartment = this.getDepartName(selectedEmp.departId);
this.ePhone = selectedEmp.empPhone;
this.eWage = selectedEmp.wages.wage;
}
}
Last year, I'm also doing the same way you did. For me, reactive forms are better. You can also search for the FormBuilder and Validators.
Hope it helps.
Related
I am currently making a small application where users can add contacts to a list. i am able to add the contacts to a list and it shows up in a separate div. at the moment when i click save, i have some code which basically has await and the whole app refreshes. the problem i am currently having is when i insert data for a user and click save it refreshes the whole screen but instead when i click save i want it to only refresh the contact component.
I currently have a piece of code which essentially refreshes all the components which is okay but now i want to try and just refresh the component i have added data too.
i have included the code below:
`
<div class="container">
<div class="main-contact-list">
<h2>Contacts</h2>
<li *ngFor="let contact of contacts;">
<button type="button" (click)="getContact(contact.id)">
<span class="name"> {{contact.firstName}} {{contact.lastName}}</span>
</button>
</li>
</div>
<div class="form">
<form [formGroup]="fg">
<div class="actionBtns">
<button class="btn btn-primary" (click)="saveContact()">Edit/Save</button>
<div class="divider"></div>
<button class="btn btn-primary" (click)="deleteContact(contact.id)">Delete</button>
</div>
<div class="row" class="row-object">
<input type="text" class="form-control" [(ngModel)]="contact.firstName" name="firstName"
formControlName="firstName" placeholder="First Name" />
<div class="divider"></div>
<input type="text" class="form-control" [(ngModel)]="contact.lastName" name="lastName"
formControlName="lastName" placeholder="Last Name" />
<div class="col">
<input type="text" class="form-control" [(ngModel)]="contact.emailAddress" name="emailAddress"
formControlName="emailAddress" placeholder="Email Address" />
<div class="divider"></div>
<input type="text" class="form-control" [(ngModel)]="contact.address1" name="address1"
formControlName="address1" placeholder="Address1" />
<div class="divider"></div>
<input type="text" class="form-control" [(ngModel)]="contact.address2" name="address2"
formControlName="address2" placeholder="Address2" />
<div class="divider"></div>
<input type="text" class="form-control" [(ngModel)]="contact.city" name="city"
formControlName="city" placeholder="City" />
<div class="divider"></div>
<input type="text" class="form-control" [(ngModel)]="contact.postCode" name="postCode"
formControlName="postCode" placeholder="Post Code" />
<div class="divider"></div>
</div>
</div>
</form>
<div class="activityForm" *ngIf="contact.id">
<app-activities [childItem]="contact"></app-activities>
</div>
</div>
`
`
import { Component, OnInit } from '#angular/core';
import {
FormBuilder,
FormControl,
FormGroup,
Validators,
FormsModule
} from '#angular/forms';
import { AppService } from '../app.service';
//interface for Contact
interface Contact {
id?: number;
firstName: string;
lastName: string;
emailAddress: string;
address1: string;
address2: string;
city: string;
postCode: string;
}
#Component({
selector: 'app-contact-details',
templateUrl: './contact-details.component.html',
styleUrls: ['./contact-details.component.css'],
})
export class ContactDetailsComponent implements OnInit {
constructor(private appService: AppService, private fb: FormBuilder) { }
fg!: FormGroup;
contacts: Contact[] = [];
contact: any = {};
//get the form field as a form control. it will useful for validation and etc
get firstNameField(): FormControl {
return this.fg.get('firstName') as FormControl;
}
get lastNameField(): FormControl {
return this.fg.get('lastName') as FormControl;
}
get emailAddressField(): FormControl {
return this.fg.get('emailAddress') as FormControl;
}
get address1Field(): FormControl {
return this.fg.get('address1') as FormControl;
}
get address2Field(): FormControl {
return this.fg.get('address2') as FormControl;
}
get postCodeField(): FormControl {
return this.fg.get('postCode') as FormControl;
}
async ngOnInit() {
this.initForm();
this.getContacts();
}
//form init. here we create the reactive form. https://angular.io/guide/reactive-forms
initForm(): void {
let id = Date.now() * Math.random();
this.fg = this.fb.group({
id: [id],
firstName: ['', [Validators.required]],
lastName: ['', [Validators.required]],
emailAddress: ['', [Validators.required, Validators.email]],
address1: ['', [Validators.required]],
address2: ['', [Validators.required]],
city: ['', [Validators.required]],
postCode: ['', [Validators.required]],
});
}
//save function
async saveContact() {
console.log(this.fg);
console.log(this.contact);
//if form doesn't have any validation error this if condition will executed
if (this.fg.valid) {
const newContact: Contact = {
firstName: this.fg.value.firstName,
lastName: this.fg.value.lastName,
emailAddress: this.fg.value.emailAddress,
address1: this.fg.value.address1,
address2: this.fg.value.address2,
city: this.fg.value.city,
postCode: this.fg.value.postCode,
};
if (this.contact?.id) {
this.appService
.editContacts(this.contact.id, newContact).subscribe();
} else {
this.appService
.addContacts(newContact).subscribe();
}
this.fg.reset(); //resetting the form array
await this.refresh();
} else {
console.log('this is invalid ');
}
}
refresh(): void {
window.location.reload();
}
async getContacts(): Promise<void> {
await this.appService
.getContacts()
.subscribe((contacts: any) => (this.contacts = contacts));
}
edit(id: number): void {
const data = this.contacts[id];
this.fg.patchValue(data);
this.refresh();
}
getContact(id: number | undefined) {
this.appService
.get(id)
.subscribe((contact: any) => (this.contact = contact));
}
selectContact(contact: Contact) {
this.contact = contact;
}
deleteContact(id: number | undefined) {
this.appService.deleteContact(id).subscribe();
this.refresh();
}
}
`
I did manage to figure this problem out. Most tutorials were stating that you basically use the router route so when something happens to refresh the route and it should show the new page.
Instead I just added #Input in front of my array and object, so when in my main HTML page I am using the *ngFor statement to iterate through the array, every time it is updated it automatically shows the new list
I am trying for 3 day and looking for a solution in to fix this problem but I am not success. I have read a problem with the same title but it did not help me in solving because it is different from my problem.
I hope that someone can help me .
Problem Description :
I have a Modal which send from one component to another component , this Modal should allow the user to Update the Student Information after calling the Method onUpdate() .
so I have Component A and Child A and the exchange some Data by using service file .
Component A has the Method onUpdate (userData) --> send to service --> Child A
javaScriptCode for Component A
onUpdate(userId: number, index: number) {
this.isOnDeleteORUpdate = true;
**// here the data will be fetched from DB and send to the Service,
// so that can be shown in Modal Form**
if (this.isOnDeleteORUpdate) {
this.requestService.getUserWithId(userId).subscribe((userData) => {
this.theModalServiceUpdate.setUser(userData);
this.theModalServiceUpdate.setUser(userData);
if (userData.courses.length <= 0 || userData.courses == null) {
this.loadedCourses = [];
this.theModalService.setCourses([]);
} else {
this.loadedCourses = userData.courses;
this.theModalService.setCourses(userData.courses);
}
});
this.modalService
.open(this.theModalServiceUpdate.modalTemplate, { centered: true })
.result.then(
(res) => {
this.closeModal = `Closed with: ${res}`;
},
(res) => {
this.closeModal = `Dismissed ${this.getDismissReason(res)}`;
}
);
}
}
Modal HTML Code:
<ng-template #modalData let-modal>
<div class="modal-dialog-scrollable modal-dialog-centered" id="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modal-basic-title">Modal title</h5>
<button
type="button"
class="btn-close"
data-dismiss="modal"
aria-label="Close"
(click)="modal.dismiss('Cross click')"
></button>
</div>
<div class="modal-body">
<form [formGroup]="userForm">
<label for="firstName">First Name</label>
<input
type="text"
class="form-control"
name="firstName"
formControlName="firstName"
/>
<label for="lastName">Last Name</label>
<input
type="text"
class="form-control"
name="lastName"
formControlName="lastName"
/>
<label for="email">Email</label>
<input
type="email"
class="form-control"
name="email"
formControlName="email"
/>
<label for="address">Address</label>
<input
type="text"
class="form-control"
name="address"
formControlName="address"
/>
<label for="telNumber">Telfone no.</label>
<input
type="text"
class="form-control"
name="telNumber"
formControlName="telNumber"
/>
<label for="gebDatum">gebDatum</label>
<input
type="text"
class="form-control"
name="gebDatum"
formControlName="gebDatum"
/>
</form>
<div class="card-body">
<div
style="
border-radius: 6px;
overflow: hidden;
border: 0.05em solid rgb(218, 231, 198);
"
>
<table class="table table-hover table-responsive">
<thead style="background-color: gray; text-align: center">
<tr>
<th scope="col">Id</th>
<th scope="col">Course Name</th>
<th scope="col">Serial Number</th>
</tr>
</thead>
<tbody>
<tr
*ngFor="let course of loadedCourses"
style="text-align: center"
>
<td>{{ course.id }}</td>
<td>
<input type="text" [value]="course.name" />
</td>
<td>
<input type="text" [value]="course.serialNumber" />
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="modal-footer">
<button (click)="saveData()" type="button" class="btn btn-danger">
Close
</button>
</div>
</div>
</div>
</ng-template>
its work for me fine and the Student Data are fetched from DataBase in the Input fields .
but I can't inter Any Information , the Input Field is frozen only I can inter the Courses Information because I user the [value] data binding in HTML instead of ngForm.
see photo: as you can see the Modal divided in tow section , in the upper one I get the data from DB but I can't modify it. in the Table Section because I am using the data binding and not the ngForm so I can enter information .
The code in JavaScript look like the following :
import { Component, OnInit, TemplateRef, ViewChild } from '#angular/core';
import { FormControl, FormGroup, Validators } from '#angular/forms';
import { courses } from 'src/app/userInfo/courses.module';
import { userInfo } from 'src/app/userInfo/user.module';
import { modalServiceUpdate } from '../../modal.updateUser.service';
#Component({
selector: 'app-modal-update-student',
templateUrl: './modal-update-student.component.html',
styleUrls: ['./modal-update-student.component.css'],
})
export class ModalUpdateStudentComponent implements OnInit {
#ViewChild('modalData') templateRef: TemplateRef<any>;
userForm: FormGroup;
loadedUser: userInfo;
lodedUserId: number = 0;
loadedCourses: courses[] = [
{
id: 0,
name: 'undefine',
serialNumber: 0,
},
];
user: userInfo = {
id: 0,
firstName: 'undefined',
lastName: 'undefined',
email: '',
gebDatum: 0,
telNumber: 0,
address: '',
courses: [],
};
constructor(private modalServiceUpdate: modalServiceUpdate) {}
loadedUserFromService: userInfo;
ngOnInit(): void {}
ngDoCheck(): void {
this.initForm();
}
private initForm() {
this.modalServiceUpdate.modalTemplate = this.templateRef;
let firstName = '';
let lastName = '';
let email = '';
let address = '';
let telNumber = 0;
let gebDatum = '0';
const user = this.modalServiceUpdate.getUser();
this.loadedCourses = this.modalServiceUpdate.getUser().courses;
firstName = user.firstName;
lastName = user.lastName;
email = user.email;
address = user.address;
telNumber = user.telNumber;
gebDatum = '0';
this.userForm = new FormGroup({
firstName: new FormControl(firstName, Validators.required),
lastName: new FormControl(lastName, Validators.required),
email: new FormControl(email, Validators.required),
address: new FormControl(address, Validators.required),
telNumber: new FormControl(telNumber, Validators.required),
gebDatum: new FormControl(gebDatum, Validators.required),
});
}
saveData() {}
}
the second issue , if I don't use the ngDoCheck() , the data that comes from other Component(Component A) will not be fired before the onUpdate() is called. so with ngOnInit() I will get undefined or empty userData .
is there alternative that can I use , to inform Angular about any changes happen on the userData that saved in Service.ts ?
I hope that some one can help me .
Thank you
am sending an put request based on these files.
Venue.ts file
export class Venue {
id: number;
venueName: string;
cityName: string;
emailContact: string;
fighter1: string;
fighter2: string;
dateOfFight: Date;
active: boolean;
}
My Angular Component files:
create-venue.component.html
<h3>Create Event</h3>
<div [hidden]="submitted" style="width: 400px;">
<form (ngSubmit)="onSubmit()">
<div class="form-group">
<label for="name">Venue Name</label>
<input type="text" class="form-control" id="venueName" required [(ngModel)]="venue.venueName" name="venueName">
</div>
<div class="form-group">
<label for="name">City Name</label>
<input type="text" class="form-control" id="cityName" required [(ngModel)]="venue.cityName" name="cityName">
</div>
<div class="form-group">
<label for="name">Email Contact</label>
<input type="text" class="form-control" id="emailContact" required [(ngModel)]="venue.emailContact" name="emailContact">
</div>
<div class="form-group">
<label for="name">Fighter 1 Contact</label>
<input type="text" class="form-control" id="fighter1" required [(ngModel)]="venue.fighter1" name="fighter1">
</div>
<div class="form-group">
<label for="name">Fighter 2 Contact</label>
<input type="text" class="form-control" id="fighter2" required [(ngModel)]="venue.fighter2" name="fighter2">
</div>
<div class="form-group">
<label for="name">Choose a time for your Event:</label>
<input type="datetime-local" class="form-control" id="dateOfFight" min="2021-01-01T00:00" max="2023-06-14T00:00" required [(ngModel)]="venue.dateOfFight" name="dateOfFight">
</div>
<button type="submit" class="btn btn-success">Submit</button>
</form>
</div>
<div [hidden]="!submitted">
<h4>You submitted successfully!</h4>
<!-- <button class="btn btn-success" (click)="newVenue()">Add</button> -->
</div>
create-venue.component.ts
import { VenueService } from '../venue.service';
import { Venue} from '../venue';
import { Component, OnInit } from '#angular/core';
import { Router } from '#angular/router';
#Component({
selector: 'app-create-venue',
templateUrl: './create-venue.component.html',
styleUrls: ['./create-venue.component.css']
})
export class CreateVenueComponent implements OnInit {
venue: Venue = new Venue();
submitted = false;
constructor(private venueService: VenueService,
private router: Router) {}
ngOnInit() {
}
newVenue(): void {
this.submitted = false;
this.venue = new Venue();
}
save() {
this.venueService.createVenue(this.venue)
.subscribe(data => console.log(data), error => console.log(error));
this.venue = new Venue();
this.gotoList();
}
onSubmit() {
this.submitted = true;
this.save();
}
gotoList() {
this.router.navigate(['/venues']);
}
}
My current sent data in chrome:
I am quite new to javascript and angular, maybe this was answered before but I have no idea how to get the input data into the Venue object...
Edit:
This is my header tab:
I
using a string instead of Date type for the dateOfFight property will let you post to the backend without issue.
You can then generate the date with new Date(datestring) on your server if needed. On the front end you can look into date pipes which will help you format the string accordingly.
You also seem to not be capturing any values in your date input. Notice venue.dateOfFight is not even there. Perhaps try logging out your data before posting
You can use a string instead of date type dateOfFight: string;, and before saving, trasform it into a date format with Moment js.
moment(Date.now()).format('YYYY-MM-DD').toString()
I have created a dynamic form field that I add and remove through a callback function on buttons DelBtn() to remove item and AddBtn() to add item
Each of this form fields have a value input
I also have a totalval field. I expect the sum of values in all the value field not to exceed the totalval. If it does we display an a error message and if the value equals we make the reason form field appear.
Example:
If I have totalValue = 100 . Now lets say I have my first form field value = 90.
Then I duplicate the form and in the next field set value = 10 then the reason field should appear because 90 + 10 = 100.
As the totalValue has been reached the reason form field should appear and the add button should be disabled.
If in the second attempt if the user tries to enter a value more than 10 then an error message should be shown.
Below is my current code
In my TS File I have
ischecks: boolean = true;
formsArray = [""];
count: number = 0;
totalval: number = 100;
ngOnInit(): void {}
constructor() {}
clickCount(): void {
this.count++;
}
DelBtn = delIndex => this.formsArray.splice(delIndex, 1);
AddBtn = () => this.formsArray.push("");
HTML
<h2> Form</h2>
<pre style="font-weight: bolder;font-family:verdana;margin-left: 35px;">Total Value:{{totalval}} </pre>
<div *ngFor="let i of formsArray; let a = index">
<div>
<form>
<table>
<div>
<label for="fname">Value:</label><br>
<input type="text" id="fname" name="fname" ><br>
<tr>
<td>
<button type="button" class="btn btn-outline-success"
style="border-radius:40px;margin-left: 50px" (click)="DelBtn(a)" ><span class="fa fa-plus"></span>Delete</button>
</td>
</tr>
<tr>
</div>
</table>
</form>
</div>
</div>
<div *ngIf=ischecks style="margin-left:35%">
<label for="fname">Reason:</label><br>
<input type="text" id="fname" name="fname" ><br>
</div>
<br>
<button type="button" class="btn btn-outline-success"
style="border-radius:40px;margin-left: 50px;margin-bottom: 30%;" (click)="AddBtn()" ><span class="fa fa-plus"></span>Add</button>
https://stackblitz.com/edit/angular-ivy-3pbdwv?file=src%2Fapp%2Fapp.component.html
Note: If you do not understand the question feel free to ask me in comments adn I am working in angular(typescript)
This will be difficult to achieve with basic Javascript. Below approach uses ReactiveForm approach
We Follow the below steps
Add the ReactiveFormsModule to the imports array of the module
#NgModule({
imports:[ ReactiveFormsModule, ... ],
Inject the FormBuilder class
constructor(private fb: FormBuilder) {}
Define the form
myForm = this.fb.group({
totalVal: [100],
formsArray: this.fb.array([this.fb.control("", { validators: [Validators.required] })]),
reason: ["", [Validators.required]]
}, { validators: [sumMatches] });
We have added a cusom validator sumMatches. We will use this to check whether the sum of the total value has been matched
function sumMatches(control): ValidationErrors | undefined {
const totalVal = Number(control.get("totalVal").value);
const formsArrayTotal = control
.get("formsArray")
.value.reduce((a, b) => Number(a) + Number(b), 0);
if (formsArrayTotal !== totalVal) {
return {
sumMismatch: true
};
}
return;
}
Next we define helper getter functions to extract properties from the formGroup
get sumMismatch(): boolean {
return this.myForm.hasError('sumMismatch')
}
get arrayFullyFilled() {
return !this.formsArray.controls.some(item => item.errors)
}
get formsArray() {
return this.myForm.get("formsArray") as FormArray;
}
get totalVal() {
return this.myForm.get("totalVal") as FormControl;
}
We also need to amend the functions to add and remove items from the formArray
DelBtn = delIndex => this.formsArray.controls.splice(delIndex, 1);
AddBtn = () => this.formsArray.push(this.fb.control(""));
Finally we can implement the formGroup in the html
<h2> Form</h2>
<span class='totalVal'>Total Value:{{ totalVal.value }}</span>
<form [formGroup]='myForm'>
<ng-container formArrayName='formsArray'>
<table *ngFor="let item of formsArray.controls; let i = index">
<tr>
<td>
<div>
<label [attr.for]="'fname' + i">Value:</label><br>
<input type="number" [formControlName]="i" type="text" [id]="'fname' + i" name="fname" ><br>
</div>
</td>
<td>
<button type="button" class="btn btn-outline-success"
s (click)="DelBtn(i)" ><span class="fa fa-plus"></span>Delete</button></td>
<tr>
</table>
</ng-container>
<div *ngIf='!sumMismatch && arrayFullyFilled'>
<label for="fname">Reason:</label><br>
<input type="text" id="fname" name="fname" ><br>
</div>
<br>
<button type="button" class="btn btn-outline-success"
(click)="AddBtn()" ><span class="fa fa-plus"></span>Add</button>
<br>
<span class="error" *ngIf="sumMismatch && myForm.touched">Total Value Mismatch</span>
</form>
I have extracted css to own file
.totalVal {
font-weight: bolder;
font-family: verdana;
}
.btn-outline-success {
border-radius: 40px;
margin-left: 50px;
}
.error {
color: red;
}
See this Demo
Edit 1 - How Does the validator work?
To understand this we look at how we build our form group. We defined a structure that produces a value in the form
{
totalVal: 100,
formsArray: [''],
reason: ''
}
By defining our form group as this.fb.group({ ... }, {validators: [ sumMatches ] } the form group with the above value will be passed to the sumMatches function
In the sumMatches we will have a something like a formGroup with the value
{
totalVal: 100,
formsArray: ['50', '20', '10'],
reason: ''
}
In the above we simply extract the 100 from the formGroup using control.get('totalVal').value same to formArray. Since formArray value will be an array then we can use reduce function to sum this.. We finally compare this and return null if they match and an Object if they do not match.
With the above approach, angular reactive forms will update the value of the form valid status based on what is provided by the user. We can hence leverage this valid status to update the UI
arrayFullyFilled()
get arrayFullyFilled() {
return !this.formsArray.controls.some(item => item.errors)
}
The above code tries to find if the user has filled ALL the inputs in the array. In our array we get all the controls, check if some of them have errors and if any has error return false otherwise return true. This is made possible considering that in my formGroup I had made the formControls as required using Validators.required validation
Actually i want to detect the changes of input and dropdown field on lostfocus/blur.
constructor Code:
constructor(private schemaCreationService: SchemaCreationService, private formBuilder: FormBuilder) {
this.schemaForm = this.formBuilder.group({
definition : this.formBuilder.group({
fieldName: ['', {
validators: [Validators.required], updateOn: 'blur'}],
type: ['', Validators.required]
}, { updateOn: 'blur' })
});
this.definition = this.formBuilder.array([]);
}
I'm trying to findout the changes but it's not working
here is the code for detecting the changes
ngOnInit() {
this.schemaForm.addControl('rows', this.definition);
this.definition.push(this.createItemFormGroup());
this.onChanges();
}
get definitionArray() {
return this.schemaForm.get('rows') as FormArray;
}
// here i'm subcribing the changes two ways one is commented but both are not working. please help me anyone to achieve this. If need more details on this please let me know.
onChanges(): void {
this.definitionArray.valueChanges.subscribe(values => {
console.log(values);
});
/* const control = this.schemaForm.controls.rows as FormArray;
for (let i = 0; i < control.length; i++) {
control.controls[i].get('fieldName').valueChanges.subscribe(x => {
console.log(x);
});
} */
}
HTML:
<tr *ngFor="let row of schemaForm.get('rows')?.controls;let index = index;">
<td>
<input type="text" class="form-control" [formControl]="row.get('fieldName')"/>
<!-- <div *ngIf="submitted && fieldName.errors" class="invalid-feedback">
<div *ngIf="fieldName.errors.required">Column Name is required</div>
</div>-->
</td>
<td>
<!-- <input [formControl]="row.get('fieldtype')">-->
<select [formControl]="row.get('type')" class="form-control" name="type" (change)='onDataTypeChange($event.target.value, index)' required>
<option value="lookup">Lookup</option>
<option value="number">Number</option>
<option value="string">Text</option>
<option value="formula">Formula</option>
</select>
</td>
<td>
<span (click)="onAddRow(index)"> <i class="fa fa-plus-circle icon-plus-color"></i></span>
<span (click)="onRemoveRow(index)"><i class="fa fa-minus-circle icon-minus-color"></i></span>
<!-- <th scope="col"><button (click)="onAddRow()">Add Columns</button></th>-->
</td>
I just removed the native html form validation required and it works perfectly.
Working Demo