Access service from Custom Validator in Angular - javascript

I'm trying to access my service in order to make check for the validator but all i get is console full of errors I'm sure I'm just bad with syntax stuff =/
validator:
import { DataService } from './services/data.service';
import { AbstractControl, FormGroup } from '#angular/forms';
export function titleValidator(control: AbstractControl,dataService:DataService) {
console.log(dataService.moviesArray) -->> How can I access this service?
if (control && (control.value !== null || control.value !== undefined)) {
if (control.value=="test") {
return {
isError: true
};
}
}
return null;
}
component:
this.movieForm = this.fb.group({
title: ['', [Validators.required,titleValidator]],
...
});
}
If anyone has even another solution to make the custom validation in the component itself I would like any help.. thanks!
update: the errors:
AddMovieComponent_Host.ngfactory.js? [sm]:1 ERROR TypeError: Cannot read property 'moviesArray' of undefined
at titleValidator (validator.ts:8)
at forms.js:602
at Array.map (<anonymous>)
at _executeValidators (forms.js:602)
at FormControl.validator (forms.js:567)
at FormControl.push../node_modules/#angular/forms/fesm5/forms.js.AbstractControl._runValidator (forms.js:2510)
at FormControl.push../node_modules/#angular/forms/fesm5/forms.js.AbstractControl.updateValueAndValidity (forms.js:2486)
at new FormControl (forms.js:2794)
at FormBuilder.push../node_modules/#angular/forms/fesm5/forms.js.FormBuilder.control (forms.js:5435)
at FormBuilder.push../node_modules/#angular/forms/fesm5/forms.js.FormBuilder._createControl (forms.js:5473)

You have to pass the service to the validator, there is no dependency injection here as this is not an Angular directive, it is a pure function. The way to do this is to use a factory method that accepts the service and creates a validator function.
export function titleValidator(dataService:DataService): ValidatorFn {
return (control: AbstractControl) => {
console.log(dataService.moviesArray) // now you can :)
// Test for control.value only, for eg:
if (control.value && dataService.moviesArray.includes(control.value))
return null;
else
return { 'movieNotFound' : { value: control.value } };
}
}
Usage:
this.movieForm = this.fb.group({
title: ['', [
Validators.required,
titleValidator(this.dataService)
]],
...
});
There is no need to check for the presence of control as Angular only calls the validator function with a valid control. Test only the value. More info here

Related

How to write global custom validation in vue3?

Presently working in vue3 and using the validation as below -
const validationRule = object({
name: string()
.required("This field is required")
.max(128, maxMessage("Student Name", 128))
.test("Check-unique-field", function (Fieldvalue) {
const checkValidation = uniquenessValidate(Fieldvalue, targetUniqueNames);
if (!checkValidation ) {
return this.createError({
path: this.path,
message: uniqueMessage("Student Name")
});
} else {
return true;
}
})
In this scenario, I write a custom validation that is uniquenessValidate using the function in form. This is working absolutely fine but the problem this code need to repeatedly using for each and every form to check the uniqueness which I not want to do. I want to write this function in a global places and uses it whenever I need to use the function to call by. Now the problem is when I written the code globally it create to issues to pass the this.createError and this.path . Can we get an idea to write this function globally?
Writing the global function I tried out as below -
import {
uniqueMessage
} from "#/core/libs/test-veevalidate-validations";
import { uniquenessValidate} from "#/core/libs/ test-veevalidate-validator";
import { computed, ComputedRef, defineComponent, ref, toRef } from "vue";
export function fn_uniqueValidator( fieldValue:string, targetValue: ComputedRef<(string | null | undefined)[]>){
const checkValidation = uniquenessValidate(fieldValue, targetValue );
if (!checkValidation ) {
return this.createError({
path:this.path,
message: uniqueMessage("Student Name")
});
} else {
return true;
}
}

bind global value into ValidationErrors in angular

i try to bind value into ValidationErrors.
i have this method:
isUniqueEmail(control: FormControl): ValidationErrors {
if (control.value != null) {
console.log(control.value)
if(control.value == this.foundEmail){
console.log("found one");
return {isUniqueEmail: true}
}else{
return null;
}
}
}
this method check if control.value (email typing) equal email stored in global variable this.foundEmail then we have duplicate email.
My problem is: i can retreive data from foundEmail in this method because this method is private.
this method is located inside export class exampleComponent implements OnInit.
Error: ERROR TypeError: Cannot read properties of undefined (reading 'foundEmail')
But i check i have data into foundEmail
The validator function gets called from the FormControl so its context is not bound to the class you're defining the method on. You need to manually bind isUniqueEmail() to this.
Two options:
Use bind() when defining the FormControl:
name: new FormControl("", [
this.isUniqueEmail.bind(this),
]),
Define your validator as arrow function:
isUniqueEmail = (control: FormControl) => {
if (control.value != null) {
console.log(control.value)
if(control.value == this.foundEmail){
console.log("found one");
return {isUniqueEmail: true}
}else{
return null;
}
}
}

Assign class instance property a value based on its type in Typescript Angular

I don't know if this is allowed in Typescript, but I'm working in an Angular 7 project and I want to instantiate a Page class fullfilling all his properties from DB object. These are my classes:
export class User {
id: number;
name: string;
created_at: string;
constructor(obj?: any) {
Object.assign(this, obj);
}
getName(): string {
return this.name;
}
}
export class Page {
id: number;
title: string;
author: User;
constructor(obj?: any) {
Object.assign(this, obj);
}
showTitle(): string {
return this.title;
}
}
Here is an example of my service method to retrieve the data:
import { HttpClient } from '#angular/common/http';
import { Injectable } from '#angular/core';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { Page } from '../models/page';
#Injectable()
export class PageService {
constructor(httpClient: HttpClient) {}
getPage(id: number): Observable<Page> {
return this.httpClient
.get<Page>('http://<my-server-ip>:<port>/api/pages')
.pipe(
map((page: Page) => {
console.log('retrieved', page);
return new Page(page);
})
);
}
}
And here is an example of this function call in my component
export class MyCustomComponent implements OnInit {
constructor(pageService: PageService) {}
ngOnInit() {
this.pageService.getPage()
.subscribe((page: Page) => {
console.log(page.showTitle());
});
}
}
This example works, but when I want to access to User methods, like:
console.log(page.author.getName());
I don't have access to them because it is not an instantiation of User class.
The same would happen with Page if I do not return a new instance of page class as an observable, thats why I use return new Page(page) after retrieving the data.
The problem is that I want to keep my constructors as generic as possible, so creating a constructor to assign the value manually (e.g.: this.author = new User(obj.author);) is not a valid workaround, as I want to implement it in every model or create a GenericModel then extend all my models.
Is there a way to fill a property with defined type in a instantiated class depending in its type?
This is what I tried so far, but it doesn't work:
export class Page {
// ...
constructor(obj?: any) {
Object.keys(obj).forEach((key: string, index: number) => {
if (typeof(obj[key]) === 'object' && obj[key] !== null) {
this[key] = new (this[key].constructor)(obj[key]);
} else {
this[key] = obj[key]
}
});
}
}
ERROR TypeError: Cannot read property 'author' of null
ERROR TypeError: Cannot read property 'constructor' of undefined
I understand that this is null when constructor is called, but I couldn't find another way to fill author property with a new instance to access to methods. Also, if I get a standard/default object like { ... }, the if will trigger and probably will throw an error too, as it does not have a constructor.
You could use Object.assign like this:
getPage(id: number): Observable<Page> {
return this.httpClient
.get<Page>('http://<my-server-ip>:<port>/api/pages')
.pipe(
map((page: Page) => {
console.log('retrieved', page);
return Object.assign(new Page(), page);
})
);
}
This code creates a new Page instance and then copies over all of the properties from the returned response (page in this example).
Then you don't need to modify your constructors.
UPDATE
NOTE: The spread syntax only copies over the properties, so I changed to use Object.assign instead.

How to Add Custom Validation Error Message for Custom Validator in Angular

I'm using reactive angular forms and created new custom form validator but its not showing custom messages I wanted to add custom message for custom validator.
I'm trying to ignore static message I want that message to be added in that validator itself so it can show for wherever places I use that validator.
custom validator codes :
import { FormControl } from '#angular/forms';
export function validateJson(input: FormControl): object | null {
try {
if (input.value) {
JSON.parse(input.value);
}
return null;
} catch (error) {
return { invalidFormat: true };
}
}
just change invalidFormat property's value to object with property message instead of true
import { FormControl } from '#angular/forms';
export function validateJson(input: FormControl): object | null {
try {
if (input.value) {
JSON.parse(input.value);
}
return null;
} catch (error) {
return { invalidFormat: {message: "your message here"} };
}
}
and in html if error exists display message like so
<div *ngIf="formControl.errors.invalidFormat && formControl.dirty">
{{ formControl.errors.invalidFormat.message}}
</div>

Form asynchronous validation in angular2

Am new to angular2 and i would like to validate an email address from the server but it fails
This is my form
this.userform = this._formbuilder.group({
email: ['', [Validators.required], [this._validationService.emailExistsValidator.bind(this)]],
});
Then the _ValidationService i have
The validation service is a service with #Injector
#Injectable()
export class ValidationService{
constructor(
private _authService:AuthService
){}
emailExistsValidator(control) {
if (control.value != undefined) {
return this._authService.checkExists("email")
.map(response => {
if (!response) {
return {'emailNotExists': true};
}
});
}
}
}
And in the authservice i have (which is another service performing the http requests)
#Injectable()
export class AuthService {
checkExists(value):Observable<any>{
return this._http.get(this.authurl+value)
.map(response => {
return response //this is either true or false
});
}
}
I have followed This link in setting up my form but it fails
The error returned is
Cannot read property 'checkExists' of undefined
at UsersComponent.webpackJsonp.187.
ValidationService.emailExistsValidator
What could be wrong
If this should point to the ValidationService, bind() needs to be
this.userform = this._formbuilder.group({
email: ['', [Validators.required], [this._validationService.emailExistsValidator.bind(this._validationService)]],
});

Categories