Angular 6 input range validation - angular6

I have to validate one of the input element in my ngForm
How to validate range while submit that form
For example user should enter the price between $1000 to $2000
Please give the suggestions to proceed
Thanks

Try this
<form [formGroup]="myForm">
<label for="priceRange">Price Range: </label>
<input type="number" id="priceRange" formControlName="priceRange">
<div *ngIf="f.priceRange.errors">
Invalid Price Range
</div>
in component.ts
import { FormBuilder, FormGroup, Validators, ReactiveFormsModule } from '#angular/forms';
myForm = new FormGroup({});
get f() {
return this.myForm.controls;
}
constructor(private formBuilder: FormBuilder){
this.myForm = formBuilder.group({
priceRange: ['', [Validators.min(1000), Validators.max(2000)]]
});
}

Try this working Example
link
<h3>Reactive Forms Validator Example</h3>
<br>
<label>We have created two validators using slightly different approaches that validate if the input is equal to "A" or not.</label>
<br><br>
<label>Doesn't work because the method is not executed which will return the custom validator function.</label><br>
<input type="text" [formControl]="wrongOnlyA">
<br><br>
<label>Works because the method is executed.</label><br>
<input type="text" [formControl]="correctOnlyA">
<br><br>
<label>Works because the validator function is directly exported.</label><br>
<input type="text" [formControl]="onlyB">
.ts
import { Component, OnInit } from '#angular/core';
import { FormGroup } from "#angular/forms"
import { RxFormBuilder } from '#rxweb/reactive-form-validators';
import { FormBuilderConfiguration } from '#rxweb/reactive-form-validators';
import { EmployeeInfo } from '../employee-info.model';
#Component({
selector: 'app-employee-info-add',
templateUrl: './employee-info-add.component.html'
})
export class EmployeeInfoAddComponent implements OnInit {
employeeInfoFormGroup: FormGroup
constructor(
private formBuilder: RxFormBuilder
) { }
ngOnInit() {
let employeeInfo = new EmployeeInfo();
let formBuilderConfiguration = new FormBuilderConfiguration();
formBuilderConfiguration.validations = {
age : {
range : {minimumNumber:18,maximumNumber:60,}
},
experience : {
range : {minimumNumber:2,maximumNumber:20,conditionalExpression:'x => x.age >=25',}
},
salary : {
range : {minimumNumber:1000,maximumNumber:200000,message:'Your Salary should be between 10000 to 200000.',}
},
};
this.employeeInfoFormGroup = this.formBuilder.formGroup(employeeInfo,formBuilderConfiguration);
}
}

Related

Not able to set default value of input (Angular)

I have a web page that uses angular form. This page is basically a user data so it shows the name, phone, mail, etc of the user.The data are obtained using a mongoDB database. I want it to show by default the value already set in placeholder and I want for the user to be possible to change it as well. If they don't type anything in the field then the value that should be passed is the placeholder. For example the value {{this.cliente.nome}} when it is in a different field than the input one but when I try to use it as default value of input it doesn't work. It says "Cannot read property 'nome' of undefined" when the other one works. The data comes correct from the mongoDB but it isn't working. This is my code:
import { Component, OnInit } from '#angular/core';
import { UserService } from '../user.service';
import { User } from 'src/user';
import { FormGroup, FormControl, FormArray, FormBuilder } from "#angular/forms";
import { Router } from '#angular/router';
#Component({
selector: 'app-cliente-dados',
templateUrl: './cliente-dados.component.html',
styleUrls: ['./cliente-dados.component.css']
})
export class ClienteDadosComponent implements OnInit {
cliente: User;
updateForm: FormGroup;
constructor(
private userService: UserService,
private formBuilder: FormBuilder,
public router: Router
) {
this.updateForm = this.formBuilder.group({
nomeUpdate: this.formBuilder.control("")
})
}
ngOnInit(): void {
this.getCliente();
}
getCliente(){
this.userService.getUser(localStorage.getItem('userAtual')).subscribe(user => {
this.cliente = user[0];
});
}
updateCliente(updateData){
console.log("update");
}
}
<form [formGroup]="updateForm" (ngSubmit)="updateCliente(updateForm.value)">
<div class="data">
<img id="iconePerfil" src="assets/Imagens/Icones/perfil.png">
<div id="informacaoRegisto">
<div class="container">
<label id="nome"><strong>{{this.cliente.nome}} <!--This one shows the value--></strong></label>
<input class="input" type=" text " [(value)]="this.cliente.nome" formControlName="nomeUpdate"> <!--Here the value isn't shown-->
<span class="border"></span>
</div>
</div>
</div>
<button type="submit" class="submit">Atualizar Dados</button>
</form>
Representation of the issue: top and bottom values are shown(not input field)
Middle one not shown(input field with default value)
You are using FormBuilder and as such the value property of input is not used. The initial value is initialized by the FormControl
Remove the following from the constructor
this.updateForm = this.formBuilder.group({
nomeUpdate: this.formBuilder.control("")
})
Modify getCliente()
getCliente(){
this.userService.getUser(localStorage.getItem('userAtual'))
.pipe(first()).subscribe(user => {
this.cliente = user[0];
this.updateForm = this.formBuilder.group({
nomeUpdate: this.formBuilder.control(this.cliente.nome)
})
});
}
Have added .pipe(first()) so only first value received is used.
Hope it helps!

How to display custom validation error message

For my form it has just one input and that's a text area, where the user enters in JSON Code and if the Text is not Valid JSON it should display an error message but for some reason it wont work.
Here's my custom validator:
import { AbstractControl, ValidationErrors, ValidatorFn } from '#angular/forms';
export function jsonValidator(control: AbstractControl): ValidationErrors | null {
try {
JSON.parse(control.value);
} catch (e) {
console.log("Not Valid JSON");
return { jsonInvalid: true };
}
return null;
};
Here is the .ts File
import { Component, OnInit } from '#angular/core';
import { FormBuilder, Validators, FormGroup } from '#angular/forms';
import { jsonValidator } from 'src/app/Validators/jsonValid';
#Component({
selector: 'app-email-body-editor',
templateUrl: './email-body-editor.component.html',
styleUrls: ['./email-body-editor.component.scss']
})
export class EmailBodyEditorComponent implements OnInit {
errorMsg : string = "Not VALID JSON";
form = this.fb.group({
jsonField: [null, [Validators.required , jsonValidator]]
});
constructor(private fb: FormBuilder) {
}
submit(): void {
console.log(this.form);
}
ngOnInit(): void {
}
}
And Finally the HTML File
<form [formGroup]="form" (submit)="submit()">
<mat-form-field appearance="fill">
<mat-label>Textarea</mat-label>
<textarea matInput
formControlName="jsonField"
cols="1000"
placeholder="my custom json here"
cdkTextareaAutosize
cdkAutosizeMinRows="10"
cdkAutosizeMaxRows="50">
</textarea>
</mat-form-field>
<br>
<div *ngIf="form.controls.jsonField.hasError('jsonValidator')">
{{errorMsg}}
</div>
</form>
Your validation error name is jsonInvalid, not jsonValidator.
The name is defined by the return statement in your validator function.
return { jsonInvalid: true };
You should use this in your HTML:
<div *ngIf="form.controls.jsonField.hasError('jsonInvalid')">
{{errorMsg}}
</div>
DEMO: https://stackblitz.com/edit/angular-h89jju

Angular TypeError: Cannot read property '0' of undefined when using event.target.file[0]

I'm currently trying to take a file input from a user and store it to Firebase Storage using AngularFire. Since it's undefined, I'm convinced that whatever file they're looking at, it's NULL, but my UI clearly shows that I'm successfully inputting a file, but the error gets caught as soon as I select the file. Am I misunderstanding how the input sends information to my TypeScript file?
Here's my TS file:
import { AngularFirestore } from '#angular/fire/firestore';
import { Component, OnInit, Input, ChangeDetectorRef } from '#angular/core';
import { finalize, tap, map } from 'rxjs/operators';
import { FormBuilder, FormGroup, FormArray, Validators } from '#angular/forms';
import { SubmitPostService } from './submit-post.service';
import { Post } from '../post.model';
import { Observable } from 'rxjs';
#Component({
selector: 'app-post-creation',
templateUrl: './post-creation.component.html',
styleUrls: ['./post-creation.component.scss']
})
export class PostCreationComponent implements OnInit {
private uuidv4 = require('uuid/v4');
// Main task
task: AngularFireUploadTask;
// Progress Monitoring
percentage: Observable<number>;
// Download URL
downloadURL: Observable<string>;
myForm: FormGroup;
post: Post;
ref: AngularFireStorageReference;
files: Observable<any>;
constructor(
private formBuilder: FormBuilder,
private postService: SubmitPostService,
private storage: AngularFireStorage,
) { }
ngOnInit() {
this.myForm = this.formBuilder.group({
title: ['', [Validators.required]],
artists: ['', [Validators.required]],
description: '',
medium: ''
});
this.myForm.valueChanges.subscribe(console.log);
}
onSubmit() {
this.post = new Post(
this.uuidv4(),
this.myForm.get('artists').value,
this.myForm.get('title').value,
new Date(),
new Date(),
`images/${Date.now()}_${this.myForm.get('title').value}`,
this.myForm.get('description').value,
this.myForm.get('medium').value
);
this.postService.submitPost(this.post);
}
upload(event: any) {
console.log('Upload successful');
try {
const file = event.target.file[0];
// The storage path
const path = `images/${Date.now()}_${file.name}`;
// Reference to storage bucket
this.ref = this.storage.ref(path);
// Main Task
this.task = this.ref.put(file);
// Tracks progress
this.percentage = this.task.percentageChanges();
this.percentage = this.task.snapshotChanges()
.pipe(map(s => (s.bytesTransferred / s.totalBytes) * 100));
this.downloadURL = this.ref.getDownloadURL();
} catch (err) { console.log(err); }
}
}
Here's my HTML:
<div>
<div class="progress">
<progress max="100" [value]="(percentage | async)"></progress>
</div>
<h1>Post Creation</h1>
<form [formGroup]="myForm" (ngSubmit)="onSubmit()">
<mat-form-field>
<input matInput placeholder="Title" formControlName="title">
</mat-form-field>
<br>
<mat-form-field>
<input matInput placeholder="Artists" formControlName="artists">
</mat-form-field>
<br>
<mat-form-field>
<input matInput placeholder="Description" formControlName="description">
</mat-form-field>
<br>
<mat-form-field>
<input matInput placeholder="Medium" formControlName="medium">
</mat-form-field>
<br>
<input type="file" (change)="upload($event)" accept=".png,.jpg">
<br>
<br>
<button mat-raised-button [disabled]="myForm.invalid" color="primary">Submit Post</button>
</form>
</div>
</body>
I've successfully created the Post objects in the Firestore, so it's not an issue of my firebase configs aren't correctly initialize.
In your upload method, in the const file = event.target.file[0]; statement, the file property should be plural

Kind of recursive usage of an Component possible?

After searching for like two hours for a solution I decided to ask some pros suspecting the solution could be quite simple.
It is an Angular7 project.
I would like to have a "goal" in my goals component with a button "+". When you click that button I want to have annother goal being added to the page. So I want to click a button of the goal component to create a new goal, which is something like recursive to me.
goals.component.html:
<input type="text" value="Ich brauche einen Laptop für maximal 1000 Euro.">
<br/>
<br/>
<app-goal id="{{lastGivenId+1}}"></app-goal>
goals.component.ts:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-goals',
templateUrl: './goals.component.html',
styleUrls: ['./goals.component.scss']
})
export class GoalsComponent implements OnInit {
lastGivenId: number = 0;
constructor() { }
ngOnInit() {
}
}
goal.component.ts and goal.component.html:
//Typescript code
import { Component, OnInit, Input } from '#angular/core';
#Component({
selector: 'app-goal',
templateUrl: './goal.component.html',
styleUrls: ['./goal.component.scss']
})
export class GoalComponent implements OnInit {
#Input() id : number;
constructor() { }
ngOnInit() {
}
onAddLowerGoal(currentGoalID:number){
// var goalElement = document.registerElement('app-goal');
// document.body.appendChild(new goalElement());
let newGoal = document.createElement("app-goal");
newGoal.setAttribute("id", "999");
let currentGoal = document.getElementById(currentGoalID.toString());
document.body.insertBefore(newGoal, currentGoal);
}
}
<html>
<div id="{{id}}" class="goal">goal{{id}}</div>
<button id="AddLowerGoal1" (click)="onAddLowerGoal(999)">+</button>
</html>
This way, it creates an app-goal element, but the div and button elements within the app-goal element is missing.
How can this problem be solved? Any help is welcome. Thanks in advance.
First glance: delete the html tags from your goal.component.html file.
Next: you can recursively add app-goal using angular. Inserting app-goal element the javascript way only adds the <app-goal></app-goal> object. It doesn't create an angular component. It doesn't bind your data.
Also if you're using Angular's #Input, you need to assign a component input with square braces. Do not use tags.
goals.component.html:
<input type="text" value="Ich brauche einen Laptop für maximal 1000 Euro.">
<br/>
<br/>
<app-goal [id]="lastGivenId+1"></app-goal>
goal.component.html:
<div id="{{id}}" class="goal">goal{{id}}</div>
<button id="AddLowerGoal1" (click)="onAddLowerGoal(999)">+</button>
<div *ngFor="let subGoal of subGoals">
<app-goal [id]="subGoal.id"></app-goal>
</div>
goal.component.ts:
import { Component, OnInit, Input } from '#angular/core';
#Component({
selector: 'app-goal',
templateUrl: './goal.component.html',
styleUrls: ['./goal.component.scss']
})
export class GoalComponent implements OnInit {
#Input() id : number;
subGoals: Array<any> = [];
constructor() { }
ngOnInit() { }
onAddLowerGoal(currentGoalID: number){
this.subGoals.push({id: currentGoalID});
}
}
You can also use a service to store your goals and subgoals to access them later.
I think what you're looking for is a Reactive Form with FormArray with dynamically added form controls.
Take a look at this for eg:
import { Component } from '#angular/core';
import { FormControl, FormGroup, FormArray, FormBuilder } from '#angular/forms';
#Component({...})
export class GoalsComponent {
goalsForm: FormGroup;
constructor(private fb: FormBuilder) {}
ngOnInit() {
this.goalsForm = this.fb.group({
goals: this.fb.array([])
});
}
onFormSubmit() {
console.log('Form Value: ', this.goalsForm.value);
}
get goals() {
return (<FormArray>this.goalsForm.get('goals')).controls;
}
addGoal() {
(<FormArray>this.goalsForm.get('goals')).push(this.fb.control(null));
}
}
And here's the template for this:
<h2>Goals:</h2>
<form [formGroup]="goalsForm" (submit)="onFormSubmit()">
<button type="button" (click)="addGoal()">Add Goal</button>
<hr>
<div *ngFor="let goal of goals; let i = index;" formArrayName="goals">
<div>
<label for="goal">Goal {{ i + 1 }}: </label>
<input type="text" id="goal" [formControlName]="i">
</div>
<br>
</div>
<hr>
<button>Submit Form</button>
</form>
Here's a Sample StackBlitz for your ref.

Angular service returns value but not displayed in page

I am learning Angular from scratch. I have created a component named 'mylink' and a service for the same.
I tried to return a string value from the service using 'observable, of' and 'subscribe'. The service returns the string, but it is not displayed in webpage. While debugging, in the component, it shows that the data received is
"Unexpected end of input". No error in console. How can I solve this? Thanks in advance.
mylink.component.ts
import { Component, OnInit } from '#angular/core';
import { MylinkService } from '../mylink.service';
import { dashCaseToCamelCase } from '#angular/compiler/src/util';
#Component({
selector: 'my-link',
templateUrl: './mylink.component.html',
styleUrls: ['./mylink.component.css']
})
export class MylinkComponent implements OnInit {
myName: String;
result: any;
constructor(private mylinkService: MylinkService) { }
ngOnInit() {
this.getMylinkData();
}
getMylinkData(): void {
this.mylinkService.getMylinkData()
.subscribe(dataV => this.myName = dataV);
}
}
mylink.service.ts
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { Observable } from 'rxjs/Observable';
import { of } from 'rxjs/observable/of';
import { catchError, map, tap } from 'rxjs/operators';
const httpOptions = {
headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};
#Injectable()
export class MylinkService {
private mylinkUrl = 'api/mylink'; // URL to web api
constructor(private http: HttpClient) { }
getMylinkData (): Observable<String> {
var val = 'From service';
return of(val);
}
}
<h2>My Link page</h2>
<div>
<label>My name is:
<input #myName />
</label>
</div>
Try like this :
<div>
<label>My name is:
<input [(ngModel)]="myName" name="myName" />
</label>
</div>
I believe what you’re trying to do is something like
<label>My name is:
{{myName}}
</label>
On the component you are assigning the returned string from the service to the public property myName. If you want to display it in the page you just need to interpolate this value as shown in my example