Value comparison in <div> using *ngFor - html

I am trying to compare values coming from database to the value I am entering on my angular 2 model driven form. I want to display a div when the values are not equal. I am trying the logic below but I am unable to make it work. Help will be appreciated.
View
<form [formGroup]="reguserform" #f="ngForm" (ngSubmit)="register()">
<fieldset>
<div class="form-group">
<label for="Username">Username</label>
<input class="form-control"
[(ngModel)]="user.Username"
type="text" id="Username"
formControlName="Username" />
</div>
<div class="alert alert-danger"
*ngIf="reguserform.controls.Username.touched && reguserform.controls.Username.errors">
<div *ngIf="reguserform.controls.Username.errors.required"
class="alert alert-danger">
Please enter a valid Username...
</div>
<div *ngFor="let r of rusers">
<div *ngIf="r.Username == user.Username" class="alert alert-danger">Username is taken</div>
</div>
</div>
</fieldset>
Component
getUsers() {
this.authenticationService.getRegUser().subscribe(
res => this.rusers = res
);
}
Everything is fine from the db end the object is being logged in console too but at the time of comparison no div is shown.

Your idea works in general, but that *ngIf="reguserform.controls.Username.touched && reguserform.controls.Username.errors" isn't true!
#Component({
selector: 'my-app',
template: `
<div>
<h2>Hello {{name}}</h2>
<form [formGroup]="reguserform" #f="ngForm" (ngSubmit)="register()">
<fieldset>
<div class="form-group">
<label for="Username">Username</label>
<input class="form-control"
[(ngModel)]="user.Username"
type="text" id="Username"
formControlName="Username" />
</div>
<div class="alert alert-danger">
<div *ngFor="let r of rusers">
<div *ngIf="r.Username == user.Username" class="alert alert-danger">Username is taken</div>
</div>
</div>
</fieldset>
</form>
</div>
`,
})
export class App {
public reguserform: FormGroup; // our model driven form
user = {};
rusers = [
{ Username: 'mxii' },
{ Username: 'test' },
{ Username: 'peter' }
];
constructor(private _fb: FormBuilder) {
this.name = 'Angular2'
}
ngOnInit() {
this.reguserform = this._fb.group({
Username: ['', [<any>Validators.required, <any>Validators.minLength(1)]]
});
}
}
See my live-demo: https://plnkr.co/edit/SnHfoAL2dnuwKkrFYGzE?p=preview

When you write res => this.rusers = res I guess you put the http response in your variable. It's not an iterable object. Maybe you need to write this :
getUsers() {
this.rusers = this.authenticationService.getRegUser().map(
res => res.json()
);
}

Related

I create simple form using angular template driven form

but I got this error,
Object is possibly 'null
<span *ngIf="name.errors.minlength">You must enter atleast 3 characters
why my error object is always null,minlength is not store in my error object what is the reason for that?
My hero.ts file is,
export class Hero {
constructor(
public id: number,
public name: string,
public email: string
) { }
}
My formone.component.ts file is,
import { Component, OnInit } from '#angular/core';
import {NgForm} from "#angular/forms";
import {Hero} from "../../hero"
#Component({
selector: 'app-formone',
templateUrl: './formone.component.html',
styleUrls: ['./formone.component.css']
})
export class FormoneComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
model = new Hero(1, 'chamara','chamara#gmail.com');
submitted = false;
onSubmit() { this.submitted = true; }
get diagnostic() { return JSON.stringify(this.model); }
}
My formone.component.html file is,
<div class="container mt-3">
<div class="row">
<div class="col-md-2">
</div>
<div class="col-md-8">
<h4>Template Driven Forms</h4>
<form #formone="ngForm" (ngSubmit)="onSubmit()">
{{diagnostic}}
<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control" id="name"
required
[(ngModel)]="model.name" name="name" #name="ngModel" minlength="3" #x>
</div>
<div *ngIf="!name.valid" class="alert alert-danger" >
<span *ngIf="name.errors.minlength">You must enter atleast 3 characters</span>
<span *ngIf="name.errors.required">This field required</span>
</div>
<div class="form-group">
<label for="alterEgo">Email</label>
<input type="email" class="form-control" id="alterEgo"
[(ngModel)]="model.email" name="alterEgo">
</div>
<br>
<button type="submit" class="btn btn-primary" [disabled]="!formone.form.valid">Submit</button>
</form>
</div>
<div class="col-md-2">
</div>
</div>
</div>
Plz help me to fix this,
Your Approach seems to be fine (at least for me), might you need to take care of few things
Remove extra #X from input code (this is causing issue by misleading error checking) and try to add name?.errors?.minlength just cross check name exists while checking errors.
<input type="text" class="form-control" id="name" required
[(ngModel)]="model.name" name="name" #name="ngModel" minlength="3">
<span *ngIf="name?.errors?.minlength">You must enter atleast 3 characters</span>
You can check more about template driven error handling here:
https://medium.com/swlh/form-validation-with-angular-template-driven-forms-8e0756cbec5
Happy Coding.. :)

How can I get the value to insert into a form for edit to update the record?

First I have a table to show all the record of books, I have a button is for going to edit the record, and I want to edit on the editbook.html and when I click submit , the record will be updated. May I know how can I implement this?
<tbody>
<tr *ngFor="let book of books">
<td class="td-title">{{book.title}}</td>
<td>{{book.author}}</td>
<td>{{book.price}}</td>
<td>{{book.isbn}}</td>
<td>{{book.details.pages}}</td>
<td>{{book.details.language}}</td>
<td class="td-desc">{{book.description}}</td>
<td><button type="button"><a [routerLink]="['/editbook/', book.isbn]">Edit</a></button></td>
<td><button type="button">Delete</button></td>
</tr>
</tbody>
And now I going to edit the record when I click the edit button.
and my edit form html
editbook.html
<div *ngIf="book" class="bookdetail-block">
<div *ngFor="let bookdetail of book" class="bookdetail">
<h1>Edit Book</h1>
<form [formGroup]="editbookForm" (ngSubmit)="onSubmit()">
<label>Title: <input type="text" formControlName="title">
<div *ngIf="submitted && editbookForm.controls.title.errors" class="error">
<div *ngIf="editbookForm.controls.title.errors.required">Required</div>
</div>
</label>
<label>Author: <input type="text" formControlName="author">
<div *ngIf="submitted && editbookForm.controls.author.errors" class="error">
<div *ngIf="editbookForm.controls.author.errors.required">Required</div>
</div>
</label>
<label>Description: <textarea type="text" formControlName="description"></textarea>
<div *ngIf="submitted && editbookForm.controls.description.errors" class="error">
<div *ngIf="editbookForm.controls.description.errors.required">Required</div>
</div>
</label>
<label>Page: <input type="number" min="1" max="10000" formControlName="page">
<div *ngIf="submitted && editbookForm.controls.page.errors" class="error">
<div *ngIf="editbookForm.controls.page.errors.required">Required</div>
</div>
</label>
<label>language:
<select formControlName="language">
<option value="English">English</option>
<option value="Traditional Chinese">Traditional Chinese</option>
<option value="Simpify Chinese">Simpify Chinese</option>
</select>
<div *ngIf="submitted && editbookForm.controls.page.errors" class="error">
<div *ngIf="editbookForm.controls.page.errors.required">Please select one option</div>
</div>
</label>
<br />
<label>Price: <input type="number" formControlName="price">
<div *ngIf="submitted && editbookForm.controls.price.errors" class="error">
<div *ngIf="editbookForm.controls.price.errors.required">Required</div>
</div>
</label>
<label>ISBN: <input type="text" formControlName="isbn">
<div *ngIf="submitted && editbookForm.controls.isbn.errors" class="error">
<div *ngIf="editbookForm.controls.isbn.errors.required">Your name is required</div>
</div>
</label>
<label>Image: <input (change)="onFileSelect($event)" type="file">
<div *ngIf="imageData" class="error">
<img [src]="imageData" [alt]="editbookForm.value.name">
</div>
</label>
<label style="display:none">ImageData:
<!-- <div *ngIf="submitted && editbookForm.controls.image.errors" class="error"> -->
<input type="hidden" id="uploadImage">
<!-- </div> -->
</label>
<input type="submit" value="Update Book" class="cta">
</form>
<div *ngIf="success" class="results">
<p>The Book is updated into the record.</p>
</div>
</div>
</div>
and the editbook.ts
import { Component, OnInit } from '#angular/core';
import { FormBuilder, FormControl, FormGroup, Validators } from '#angular/forms';
import { DataService } from '../data.service';
import { ActivatedRoute, Router } from "#angular/router";
interface HTMLInputEvent extends Event {
target: HTMLInputElement & EventTarget;
}
#Component({
selector: 'app-editbook',
templateUrl: './editbook.component.html',
styleUrls: ['./editbook.component.scss']
})
export class EditbookComponent implements OnInit {
isbn: any;
book: any;
editbookForm: FormGroup;
submitted = false;
success = false;
imageData : String;
constructor(private formBuilder: FormBuilder, private data: DataService, private router: Router, private route: ActivatedRoute) { }
ngOnInit() {
this.isbn = this.route.snapshot.paramMap.get("isbn");
this.data.getOneBook(this.isbn).subscribe(data =>{
console.log({ data }); //show data
this.book = data
//console.log(this.books);
})
}
onFileSelect(event?: HTMLInputEvent){
console.log("selected file")
console.log(event)
let files: any = event.target.files[0];
console.log(files);
const reader = new FileReader();
reader.onloadend = () => {
var b64 = reader.result.toString();
let el :any = document.querySelector('#uploadImage');
el.value = b64;
}
reader.readAsDataURL(event.target.files[0]);
}
onSubmit() {
/*
// upload image
this.bookForm.reset();
this.imageData = null;
*/
this.submitted = true;
if(this.editbookForm.invalid) {
return;
}
this.data.insertBook(this.editbookForm.controls);
this.success = true;
}
}
how can I insert the value into the html input ?
Don't use ngFor for insert the value into the html input. use angular patch method.
For example:
this.bookForm.patchValue({
title: this.book.title,
author: this.book.author
});
You can also initialize value on form:
this.bookForm({
title:[this.book.title],
author:[this.book.author]
});
Suppose you have two fields for the moment (title and author), you complete the other fields later after you be sure everything is fine.
Start with a simple example(Remove the validations from HTML for now).
So, initially, your HTML should be something like this:
<form [formGroup]="editbookForm" (ngSubmit)="onSubmit()">
<label>Title:
<input type="text" formControlName="title">
</label>
<label>Author:
<input type="text" formControlName="author">
</label>
<input type="submit" value="Update Book" class="cta">
</form>
Then your OnInit should be something like this:
ngOnInit() {
this.isbn = this.route.snapshot.paramMap.get("isbn");
if (this.isbn) {
//Cleaning the form from the previous data
if (this.editbookForm) this.editbookForm.reset();
this.data.getOneBook(this.isbn)
.pipe(take(1)) //To ensure that it will unsubscribe later
.subscribe((data) => {
this.book = data;
//Filling the form
this.editbookForm.patchValue({
title: this.book.title,
author: this.book.author
});
});
}
}
If that works, step by step add validations and other things as you like.
Examples are:
<div *ngIf="submitted && editbookForm.controls.author.errors" class="error">
<div *ngIf="editbookForm.controls.author.errors.required">Required</div>
</div>
and
<div *ngIf="book" class="bookdetail-block">
<div *ngFor="let bookdetail of book" class="bookdetail">
<h1>Edit Book</h1>
and so on.

How to fetch data from database to textbox typescript

How to fetch data from database to textbox typescript? My Get function is working it display on console but not on textbox.
export class ProfileComponent implements OnInit {
Profile: Profile = new Profile;
constructor(
private ProfileService: ProfileService,
private Security: Security){
}
ngOnInit() {
this.GetProfileByID(this.Security.UserID);
}
GetProfileByID(UserID: any) {
this.ProfileService.GetProfileByID(UserID).then(
(response) => {
console.table(response.Body)
}
)
}
}
Here's my html
`
<form #updateForm="ngForm">
<div class="input-container mb-3">
<div class="col-12">
<label>* Name</label>
<input name="name" #name="ngModel" id="TACName" type="text" [(ngModel)]="Profile.Name" pInputText required/>
<div class="errortxt" [hidden]="name.valid || name.pristine" class="alert alert-danger">
<div class="errortxt" [hidden]="!name.hasError('required')"> Name is Required!</div>
</div>
</div>
</div>
<button class="ui-button-raised submit-btn" [disabled]="!updateForm.valid || !Agreement" pButton label="SAVE" type="submit" (click)="Save(updateForm)"></button>
</form>
`
here's the result on console
According the output result in the console...
GetProfileByID(UserID: any) {
this.ProfileService.GetProfileByID(UserID).then(
(response) => {
this.Profile.Name = response.Body.Name;
}
)
}
There is a typo, you should use new Profile() instead of new Profile.
Really recommending to not use [(ngModel)]. Use FormGroup instead and then after receiving your response from service, use FormGroup.get(controlName: string).patchValue. That will fix your issue for sure.

ERROR TypeError: Cannot read property ' ' of undefined

I'm trying to make a form field to add new hotel and specify the address.
I have the hotel class:
export class Hotel {
public constructor (
public name:string,
public address: Address,
){}
}
export class Address {
country:string;
town :string;
street: string;
}
this's the function addHotel in the component:
addHotel(hotel:any, address:any){
if (this.form.valid) {
let newHotel = new Hotel(hotel["name"], (hotel.address["country"], hotel.address["town"], hotel.address["street"]));
the html form is very simple:
<div class="tab-pane" >
<div class="form-group">
<label class="text-gray">Name :</label>
<div class="input-group">
<div class="input-group-addon"><i class="fa fa-envelope-o"></i></div>
<input formControlName="name" class="form-control" type="text">
</div>
</div>
</div>
<div class="tab-pane" id="address">
<div class="form-group">
<label class="text-gray">Country :</label>
<div class="input-group" >
<div class="input-group-addon"><i class="fa fa-map-marker"></i></div>
<input class="form-control" type="text">
</div>
<label class="text-gray">Town :</label>
<div class="input-group" >
<div class="input-group-addon"><i class="fa fa-map"></i></div>
<input class="form-control" type="text">
</div>
<label class="text-gray">Street :</label>
<div class="input-group" >
<div class="input-group-addon"><i class="fa fa-map-signs"></i></div>
<input class="form-control" type="text">
</div>
</div>
</div>
I even tried to add new function, addAddress:
addAddress(hotel,address):any{
//let newAddress = new Address(hotel.address["country"], ,hotel.address["town"], hotel.address["street"]);
this.address.push(hotel.address["country"], hotel.address["town"], hotel.address["street"]);
console.log(this.address);
return this.address;
}
but it always return empty array {country:null, town:null, street:null}
or the famous error: ERROR TypeError: Cannot read property 'country' of undefined
Use the safe navigation operator (?)
look like this
<p>Employer: {{address?.country}}</p>
The safe navigation operator (?) means that the employer field is
optional and if undefined, the rest of the expression should be
ignored.
Reference
https://angular.io/guide/cheatsheet
even when I add console.log(address.town); to the addAddress function, I get undefined. what I have to do??
Read this post it having all details you want : https://angular.io/guide/reactive-forms#nested-formgroups
Please define binding between template and typescript for getting value from template form control example :
export class etailComponent5 {
hotelForm: FormGroup;
constructor(private fb: FormBuilder) {
this.createForm();
}
createForm() {
this.hotelForm= this.fb.group({ // <-- the parent FormGroup
name: [''],
address: this.fb.group({ // <-- the child FormGroup
street: '',
town: '',
country: ''
})
});
}
saveform() {
const hotel:Hotel = hotelForm.value;
//or to get individual control you need to do like this
// const street= hotelForm.get('address.street').value
// const town= hotelForm.get('address.town').value
// const coutnry= hotelForm.get('address.country').value
}
}
<form [formGroup]="hotelForm" >
<div class="form-group">
<label class="center-block">Name:
<input class="form-control" formControlName="name">
</label>
</div>
<div formGroupName="address" class="well well-lg">
<h4>Secret Lair</h4>
<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">Town:
<input class="form-control" formControlName="town">
</label>
</div>
<div class="form-group">
<label class="center-block">Country:
<input class="form-control" formControlName="country">
</label>
</div>
</div>
</form>
Working :
const address = new Address();
address.country='abc';
address.street= 'abc';
address.town ='abc';
let newHotel = new Hotel('abc', address);
console.log(newHotel.name);
console.log(`${newHotel.address.country},${newHotel.address.street},${newHotel.address.town}`);
As per you structure address - property is class used in hotel, so you need to initialized it and then you can assign to address property. as given in above code..
In your code you are trying to set value without initializing it
I suggest make use of interface instead of class
export interface Hotel {
name:string;
address: Address;
}
export interface Address {
country:string;
town :string;
street: string;
}
const hotel: Hotel = { name: 'name of hotel',
address: { country:'abc', town : 'abc', city:'abc' }
};

how to works with forms in array with angular 2

I've been working with reactive form like I show in the link
https://plnkr.co/edit/ApCn3YicMjfm2vhSOudj?p=preview
this is my form
<div *ngFor="let item of data; let index = index">
<form novalidate (ngSubmit)="onSubmit(user)" [formGroup]="user">
<label>
<span>Full name</span>
<input type="text" placeholder="Name" formControlName="name">
</label>
<div class="error" *ngIf="user.get('name').touched && user.get('name').hasError('required')">
Name is required
</div>
<div class="error" *ngIf="user.get('name').touched && user.get('name').hasError('minlength')">
Minimum of 2 characters
</div>
<div formGroupName="account">
<label>
<span>Email address</span>
<input type="email" placeholder="Email" formControlName="email">
</label>
<div class="error" *ngIf="user.get('account').get('email').hasError('required') && user.get('account').get('email').touched">
Email is required
</div>
<label>
<span>Confirm address</span>
<input type="email" placeholder="Address" formControlName="confirm">
</label>
<div class="error" *ngIf="user.get('account').get('confirm').hasError('required') && user.get('account').get('confirm').touched">
Confirming email is required
</div>
</div>
<button type="submit" [disabled]="user.invalid">Sign up</button>
</form>
</div>
but my problem is that I have an ngFor, every time I submit the form it push the data to array.
How can I do if I want for example submit my first array and push the data to position 0 of my data array, if I submit my second form, it will push the data to position 1
But my second form should be empty
maybe you wanna using form array like this:
#Component({
selector: 'signup-form',
template: `
<form novalidate (ngSubmit)="onSubmit()" [formGroup]="users">
<div formArrayName="data">
<ng-container *ngFor="let user of fData.controls; index as i">
<div [formGroupName]="i">
<label>
<span>Full name</span>
<input type="text" placeholder="Name" formControlName="name">
</label>
<div class="error" *ngIf="user.get('name').touched && user.get('name').hasError('required')">
Name is required
</div>
<div class="error" *ngIf="user.get('name').touched && user.get('name').hasError('minlength')">
Minimum of 2 characters
</div>
<div formGroupName="account">
<label>
<span>Email address</span>
<input type="email" placeholder="Email" formControlName="email">
</label>
<div
class="error"
*ngIf="user.get('account').get('email').hasError('required') && user.get('account').get('email').touched">
Email is required
</div>
<label>
<span>Confirm address</span>
<input type="email" placeholder="Address" formControlName="confirm">
</label>
<div
class="error"
*ngIf="user.get('account').get('confirm').hasError('required') && user.get('account').get('confirm').touched">
Confirming email is required
</div>
</div>
<button type="submit" [disabled]="user.invalid">Sign up</button>
</div>
</ng-container>
</div>
</form>
`
})
export class SignupFormComponent implements OnInit {
user: FormGroup;
users: FormGroup;
constructor(private fb: FormBuilder) {}
ngOnInit() {
this.user = this.buildGroup();
this.users = this.fb.group({
data: this.fb.array([this.user])
});
}
get fData() {
return this.users.get('data') as FormArray;
}
buildGroup() {
return this.fb.group({
name: ['', [Validators.required, Validators.minLength(2)]],
account: this.fb.group({
email: ['', Validators.required],
confirm: ['', Validators.required]
})
});
}
onSubmit() {
this.fData.push(this.buildGroup());
const {valid, value} = this.fData;
console.log(valid, value);
}
}
basically, we're using FormArray to handle array of data, then loop through it.
in template, each time you loop through array item, Angular will store current AbstractControl in index variable (in above is i).
you can see form in action here: https://plnkr.co/edit/E5Qzm85LksSCZAloXZz5?p=preview
The API document here: https://angular.io/docs/ts/latest/api/forms/index/FormArray-class.html
you can use at, removeAt, etc to access or delete at specific index.