Writing Javascript for client-side class-level validation using PrimeFaces - javascript

I have a class-level Constraint on my class as below:
#NotEqualAccounts
public class FundTransferVO extends SignableVO implements Serializable{
private String fromAccount;
private String toAccount;
//setter,getter
}
and my custom Constraint code is:
#Target({ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
#Constraint(validatedBy = NotEqualAccountsValidator.class)
#ClientConstraint(resolvedBy=ClientNotEqualAccountsValidator.class)
public #interface NotEqualAccounts {
String message() default "{org.javaee7.validation.custom.constraint.NotEqualAccounts}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
I want to have a javaScript for client-side validation of my class using primeFace, I've already written the code below, but it doesn't work
PrimeFaces.validator['NotEqualAccounts'] = {
MESSAGE_ID: '...',
validate: function(element, fundTransferController) {
if(fundTransferController.fundTransferVO.getToAccount()===fundTransferController.fundTransferVO.getFromAccount()) {
msg = '';
throw msg;
}
}
};
fundTransferController is just my controller that my bean(fundTransferVO) is used in it.
Is there a way to validate class-level constraints on client-side using primeFace?

Related

Is it possible to access class prototype's property?

I got a question but i don't know have the right words to ask it in just one phrase.
I'm writing my code in TypeScript and I want to achieve the following:
I got an abstract "Resource" class
// Resource.ts
abstract class Resource {
public abstract readonly type: string;
protected _id?: string;
get id() {
return this._id;
}
public static info() {
return {
type: this.prototype.type
};
}
}
and, let's say, a Post resource class that inherits from the abstract class
class PostResource extends Resource {
public readonly type = 'post'
}
I want to access the "type" property from the PostResource class prototype like I tried to do with the Resource.info() static method. Obviously, it returns undefined.
I also tried to instanciate the class inside the static method like that
public static info() {
return {
type: (new this()).type
}
}
but it throws an Error because I can't instanciate Resource as it is an abstract class.
I atempted to use static properties as well :
abstract class Resource {
public static readonly type: string;
public static info() {
return {
type: this.type
}
}
}
class PostResource extends Resource {
public static readonly type = 'post';
}
That theoricaly works, but then I loose all the benefits of inheritance because static propeties and methods cannot be abstract. For example, I could create a PostResource with no type static property and TypeScript would not warn me. type would then be undefined, which is not good because all Resource-extended class should have a type property.
So I'm looking for a solution to allow me to access all properties initialized in a Resource-extended class.
I hope my question is clear, thank you for your help !
EDIT:
I should give more details about my final goal.
I would like to have a list of classes that inherit Resource abstract class, and therefore have a "type" property. Ideally it should be a static property, cause I could simply iterate over the classes and just access the property.
But I also need this value inside the instances of this class, so for example i could have something like that:
console.log(PostResource.type); // > 'post'
const post1 = new PostResource();
console.log(post1.type); // > 'post';
What about having a property _type in the abstract class and initializing it in constructor of subclasses?
abstract class Resource {
protected _type: string;
constructor(type: string) {
this._type = type;
}
public info() {
return {
type: this._type
}
}
}
class PostResource extends Resource {
constructor() {
super('post');
}
}
class GetResource extends Resource {
constructor() {
super('get');
}
}
let postResource = new PostResource();
let getResource = new GetResource();
console.log(postResource.info()); // {type: 'post'}
console.log(getResource.info()); // {type: 'get'}
Edit
I'm not sure what you're trying to achieve, but here's an example for your updated requirements:
abstract class Resource {
}
class PostResource extends Resource {
static type = 'post';
public type = 'post';
}
let postResource = new PostResource();
console.log(PostResource.type); // post
const post1 = new PostResource();
console.log(post1.type); // post
Actually your attempt with instantiating the class inside the static method can work, you just need a proper typing for this:
public static info(this: new () => Resource) {
return {
type: new this().type
}
}
Playground
More info on function's this parameter annotation.

How to block TypeScript class property or method multi-level inheritance?

Here is the next JavaScript class structure:
// data.service.ts
export class DataService {
public url = environment.url;
constructor(
private uri: string,
private httpClient: HttpClient,
) { }
getAll() {}
getOne(id: number) {}
create(data: any) {}
// etc...
}
Next is the general data model what can use the DataService's methods to communicate the server:
// Model.model.ts
import './data.service';
export class Model extends DataService {
all() {}
get() {
// parse and make some basic validation on the
// DataService.getOne() JSON result
}
// etc...
}
And finally I create a specific data model based on Model.model.ts:
// User.model.ts
import './Model.model.ts';
export class User extends Model {
id: number;
name: string;
email: string;
init() {
// make specific validation on Model.get() result
}
}
If I use the User class in my code, I can call the DataService's getAll() function directly if I want. But this is not a good thing, because in this case I miss the built-in validations.
How can I block the method inheritance on a class?
I'm looking for something like PHP's static method. The child class can use the methods, but his child can't.
I want something like this:
const dataService = new DataService();
dataService.getAll(); // void
const model = new Model();
model.getAll(); // undefined
model.all(); // void
const user = new User();
user.getAll(); // undefined
user.all(); // void
Is there any way to do this?
You can prevent it to be built when you call it by adding private keyword to the function private getAll() {}. But private is a TypeScript feature, not Javascript, so if you force it to be built, it is still callable. There'll be no way to totally prevent it this moment.
So if you want it to be prevented in TypeScript, just add private keyword there. But it is not buildable, not return undefined as you expect. Otherwise, just replace the function with an undefined-returned function on children classes
With your code as shown and use case as stated, the only way to get the behavior you want is not to make Model extend DataService at all. There is a subsitution principle which says that if Model extends DataService, then someone should be able to treat a Model instance exactly as they would treat a DataService instance. Indeed, if a Model is a special type of DataService, and someone asks for a DataService instance, you should be able to give them a Model. It's no fair for you to tell them that they can't call the getAll() method on it. So the inheritance tree can't work the way you have it. Instead you could do something like this:
// ultimate parent class of both DataService and Model/User
class BaseDataService {
getOne(id: number) { }
create(data: any) { }
// etc...
}
// subclass with getAll()
class DataService extends BaseDataService {
getAll() {}
}
// subclass without getAll()
class Model extends BaseDataService {
all() { }
get() { }
// etc...
}
class User extends Model {
id!: number;
name!: string;
email!: string;
init() { }
}
const dataService = new DataService();
dataService.getAll(); // void
const model = new Model();
model.getAll(); // error
model.all(); // okay
const user = new User();
user.getAll(); // error
user.all(); // okay
That works exactly as you've specified. Perfect, right?
Well, I get the sinking feeling that you will try this and get upset that you cannot call this.getAll() inside the implementation of Model or User... probably inside the suspiciously-empty body of the all() method in Model. And already I'm getting the urge to defensively point to the Minimum, Complete, and Verifiable Example article, since the question as stated doesn't seem to require this.
If you do require that, you still can't break the substitution principle. Instead I'd suggest making getAll() a protected method, and expose an all() method on DataService:
class DataService {
getOne(id: number) { }
create(data: any) { }
protected getAll() { }
all() {
this.getAll();
}
// etc...
}
class Model extends DataService {
all() {
this.getAll();
}
get() { }
// etc...
}
class User extends Model {
id!: number;
name!: string;
email!: string;
init() { }
}
const dataService = new DataService();
dataService.getAll(); // error
dataService.all(); // okay
const model = new Model();
model.getAll(); // error
model.all(); // okay
const user = new User();
user.getAll(); // error
user.all(); // okay
and live with the fact that getAll() is a purely internal method never meant to see the light of day.
Okay, hope one of those helps; good luck!

Workaround for accessing class type arguments in static method in Typescript

The following error
Static members cannot reference class type parameters.
results from the following piece of code
abstract class Resource<T> {
/* static methods */
public static list: T[] = [];
public async static fetch(): Promise<T[]> {
this.list = await service.get();
return this.list;
}
/* instance methods */
public save(): Promise<T> {
return service.post(this);
}
}
class Model extends Resource<Model> {
}
/* this is what I would like, but the because is not allowed because :
"Static members cannot reference class type parameters."
*/
const modelList = await Model.fetch() // inferred type would be Model[]
const availableInstances = Model.list // inferred type would be Model[]
const savedInstance = modelInstance.save() // inferred type would be Model
I think it is clear from this example what I'm trying to achieve. I want be able to call instance and static methods on my inheriting class and have the inheriting class itself as inferred type. I found the following workaround to get what I want:
interface Instantiable<T> {
new (...args: any[]): T;
}
interface ResourceType<T> extends Instantiable<T> {
list<U extends Resource>(this: ResourceType<U>): U[];
fetch<U extends Resource>(this: ResourceType<U>): Promise<U[]>;
}
const instanceLists: any = {} // some object that stores list with constructor.name as key
abstract class Resource {
/* static methods */
public static list<T extends Resource>(this: ResourceType<T>): T[] {
const constructorName = this.name;
return instanceLists[constructorName] // abusing any here, but it works :(
}
public async static fetch<T extends Resource>(this: ResourceType<T>): Promise<T[]> {
const result = await service.get()
store(result, instanceLists) // some fn that puts it in instanceLists
return result;
}
/* instance methods */
public save(): Promise<this> {
return service.post(this);
}
}
class Model extends Resource {
}
/* now inferred types are correct */
const modelList = await Model.fetch()
const availableInstances = Model.list
const savedInstance = modelInstance.save()
The problem that I have with this is that overriding static methods becomes really tedious. Doing the following:
class Model extends Resource {
public async static fetch(): Promise<Model[]> {
return super.fetch();
}
}
will result in an error because Model is no longer extending Resource correctly, because of the different signature. I can't think of a way to declare a fetch method without giving me errors, let alone having an intuitive easy way to overload.
The only work around I could get to work is the following:
class Model extends Resource {
public async static get(): Promise<Model[]> {
return super.fetch({ url: 'custom-url?query=params' }) as Promise<Model[]>;
}
}
In my opinion, this is not very nice.
Is there a way to override the fetch method without having to manually cast to Model and do tricks with generics?
You could do something like this:
function Resource<T>() {
abstract class Resource {
/* static methods */
public static list: T[] = [];
public static async fetch(): Promise<T[]> {
return null!;
}
/* instance methods */
public save(): Promise<T> {
return null!
}
}
return Resource;
}
In the above Resource is a generic function that returns a locally declared class. The returned class is not generic, so its static properties and methods have concrete types for T. You can extend it like this:
class Model extends Resource<Model>() {
// overloading should also work
public static async fetch(): Promise<Model[]> {
return super.fetch();
}
}
Everything has the types you expect:
Model.list; // Model[]
Model.fetch(); // Promise<Model[]>
new Model().save(); // Promise<Model>
So that might work for you.
The only caveats I can see right now:
There's a bit of duplication in class X extends Resource<X>() which is less than perfect, but I don't think you can get contextual typing to allow the second X to be inferred.
Locally-declared types tend not to be exportable or used as declarations, so you might need to be careful there or come up with workarounds (e.g., export some structurally-identical or structurally-close-enough type and declare that Resource is that type?).
Anyway hope that helps. Good luck!

Why duck typing is allowed for classes in TypeScript

Looks like in TypeScript it's absolutely fine (from the compiler perspective) to have such code:
class Vehicle {
public run(): void { console.log('Vehicle.run'); }
}
class Task {
public run(): void { console.log('Task.run'); }
}
function runTask(t: Task) {
t.run();
}
runTask(new Task());
runTask(new Vehicle());
But at the same time I would expect a compilation error, because Vehicle and Task don't have anything in common.
And sane usages can be implemented via explicit interface definition:
interface Runnable {
run(): void;
}
class Vehicle implements Runnable {
public run(): void { console.log('Vehicle.run'); }
}
class Task implements Runnable {
public run(): void { console.log('Task.run'); }
}
function runRunnable(r: Runnable) {
r.run();
}
runRunnable(new Task());
runRunnable(new Vehicle());
... or a common parent object:
class Entity {
abstract run(): void;
}
class Vehicle extends Entity {
public run(): void { console.log('Vehicle.run'); }
}
class Task extends Entity {
public run(): void { console.log('Task.run'); }
}
function runEntity(e: Entity) {
e.run();
}
runEntity(new Task());
runEntity(new Vehicle());
And yes, for JavaScript it's absolutely fine to have such behaviour, because there is no classes and no compiler at all (only syntactic sugar) and duck typing is natural for the language. But TypeScript tries to introduce static checks, classes, interfaces, etc. However duck typing for class instances looks rather confusing and error-prone, in my opinion.
This is the way structural typing works. Typescript has a structural type system to best emulate how Javscript works. Since Javascript uses duck typing, any object that defines the contract can be used in any function. Typescript just tries to validate duck typing at compile time instead of at runtime.
Your problem will however only manifest for trivial classes, as soon as you add privates, classes become incompatible even if they have the same structure:
class Vehicle {
private x: string;
public run(): void { console.log('Vehicle.run'); }
}
class Task {
private x: string;
public run(): void { console.log('Task.run'); }
}
function runTask(t: Task) {
t.run();
}
runTask(new Task());
runTask(new Vehicle()); // Will be a compile time error
This behavior also allows you to not explicitly implement interfaces, for example you function could define the interface for the parameter inline, and any class that satisfies the contract will be compatible even if they don't explicitly implement any interface:
function runTask(t: { run(): void }) {
t.run();
}
runTask(new Task());
runTask(new Vehicle());
On a personal note, coming from C# this was seemed insane at first, but when it comes to extensibility this way of type checking allows for much greater flexibility, once you get used to it you will see the benefits.
It is now possible to create nominal types with TypeScript that allow you to discriminate types by context. Please consider the following question:
Atomic type discrimination (nominal atomic types) in TypeScript
With it's example:
export type Kilos<T> = T & { readonly discriminator: unique symbol };
export type Pounds<T> = T & { readonly discriminator: unique symbol };
export interface MetricWeight {
value: Kilos<number>
}
export interface ImperialWeight {
value: Pounds<number>
}
const wm: MetricWeight = { value: 0 as Kilos<number> }
const wi: ImperialWeight = { value: 0 as Pounds<number> }
wm.value = wi.value; // Gives compiler error
wi.value = wi.value * 2; // Gives compiler error
wm.value = wi.value * 2; // Gives compiler error
const we: MetricWeight = { value: 0 } // Gives compiler error

With Typescript in Protractor, how can I scope an interior function so it's accessible to another function?

We are creating a library for frequently used functions in our Protractor/TypeScript project, and encountered a problem with scoping.
This is an excerpt from the TypeScript. Our problem occurs when we run the application and call for example clickBreadcrumb. The clickBreadcrumb function attempts to access the clickRepeaterElement.byName function.
export class Lib {
public clickBreadcrumb = {
byText(breadcrumbText: string) {
// This statement fails. TypeError: Cannot read property 'byName' of undefined
this.clickRepeaterElement.byName('bcItem in vm.breadCrumbs', breadcrumbText);
}
};
public clickRepeaterElement = {
byName(repeaterText:string, elementToClick:string, parentElement?:protractor.ElementFinder): void {
// Click the elementToClick.
},
byIndex(repeaterText: string, index: number) {
// Click element at the index.
},
};
}
WebStorm resolves clickRepeaterElement.byName, which essentially signals to us that this should work. But when we actually run the test, we get the following error:
TypeError: Cannot read property 'byName' of undefined
Coming from a C# background this was unexpected. How can we adjust the pattern so that this will resolve as we expect? Thanks for your help.
Javascript has weird rules when it comes to this.
In your case this points to the byText function, not the class.
I would rewrite it this way:
export class Lib {
public clickBreadcrumb = {
byText: this.byText
};
public clickRepeaterElement = {
byName: this.byName,
byIndex: this.byIndex,
};
private byText(breadcrumbText: string) {
// this is now Lib
this.clickRepeaterElement.byName('bcItem in vm.breadCrumbs', breadcrumbText);
}
private byName(repeaterText: string, elementToClick: string, parentElement ? : protractor.ElementFinder): void {
// Click the elementToClick.
}
private byIndex(repeaterText: string, index: number) {
// Click element at the index.
}
}
You can also use bind to make sure that the context of the methods have the correct value of this.
Update:
Regarding the multiple implementations question. I would propose you make use of the classes in TypeScript to structure the code a little bit differently.
export class Lib {
public clickBreadcrumb = new Breadcrumb(this);
public clickRepeaterElement = new Repeater(this);
}
export class Breadcrumb {
constructor(private lib: Lib) {}
public byText(breadcrumbText: string) {
this.lib.clickRepeaterElement.byName('bcItem in vm.breadCrumbs', breadcrumbText);
}
}
export class Repeater {
constructor(private lib: Lib) {}
public byName(repeaterText: string, elementToClick: string, parentElement ? : protractor.ElementFinder): void {
// Click the elementToClick.
}
public byIndex(repeaterText: string, index: number) {
// Click element at the index.
}
public byText(test: string) {
// some other implementation
}
}
You can also send smaller parts of the library in places, instead of sending Lib everywhere. It will also allow for better concern separation if/when your library grows.

Categories

Resources