Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add submit validation errors #35

Merged
merged 7 commits into from
Oct 11, 2023
Merged

Conversation

olistrik
Copy link
Contributor

@olistrik olistrik commented Oct 4, 2023

@jerbob92 @wouter-willems

This is what Jeroen and I discussed. I've added an error type that can be thrown from the onSubmit callback and will register message errors on the form fields based on it's path in the form. If you thow a "FormValidationError", or even an array of them, it'll work out the box. Any other error thrown will bubble up as before.

The default error handler function can be overwritten with a provider to allow for automatic, application wide error mapping. This is particularly useful for DocHorizon, as all of our validation errors from the backend follow the same schema, and 9/10 times map directly to the form structure.

@olistrik
Copy link
Contributor Author

olistrik commented Oct 4, 2023

Oh and I didn't want to keep appending to the app.component.ts so I added routing to the demo app.

@olistrik olistrik force-pushed the add-submit-validation-errors branch from b70ff10 to 377de2c Compare October 4, 2023 11:29
@@ -0,0 +1,26 @@
# https://github.com/numtide/devshell
Copy link
Contributor Author

@olistrik olistrik Oct 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this file shouldn't have ended up in here, I made a seperate branch for it, but rebase go burr i guess.

I can't develop without it as it sets up node 16 (which is no longer maintained btw, so nixos considers it insecure).

flake.nix can't, and shouldn't be, git ignored. Having to remake and remove this file every time I need to work on enhancy forms is really irritating, so it would be very helpful for me if this is in version control.

Copy link
Member

@wouter-willems wouter-willems left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@olistrik reviewed

} catch (e) {
if (e === invalidFieldsSymbol) {
return;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer to leave the comment explaining why the error was swallowed. What is the reason for removing that?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also prefer those comments! I must have removed it by mistake.

Comment on lines 4 to 5
_path: string;
_message: string;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • missing public/private.
  • What is the reason for starting with _?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

they should have both been private, that's true.

the underscore is because they clash with the public getter otherwise.

private _foo: string;
public get foo() {
  return this._foo;
}

is a common js encapsulation style. though some people prefer using $ instead of _ but I read that as sfoo.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but I've removed them in my new changes.


constructor(path: string, message: string) {
super(message);
this.name = 'FORM_VALIDATION_ERROR';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since the name is always FORM_VALIDATION_ERROR , can just be a static final constant?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As in a constant in the file? name is defined by the error interface, I can't make it static readonly in the class as that conflicts with the definition in the super class.

Comment on lines 14 to 16
get path() {
return this._path;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for consistency's sake, getPath()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could also make it like this?

class ... {
  public readonly path: string;
  private message: string;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually, this would be sufficient:

export class FormValidationError extends Error {
	public readonly name = 'FormValidationError';
	public readonly path: string;

	constructor(path: string, message: string) {
		super(message);
		this.path = path;
	}
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could also have name reference this.constructor.name. That should be static afaik.

export const KLP_FORM_ERROR_HANDLER = new InjectionToken<FormErrorHandler>('KLP_FORM_ERROR_HANDLER');

export const DefaultErrorHandler: FormErrorHandler = (error: any) => {
if (Array.isArray(error) && error.reduce((acc, err) => acc && err instanceof FormValidationError)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A reduce inside the condition is kinda hard to read. Also, this reducer does not have an initial value?

Copy link
Contributor Author

@olistrik olistrik Oct 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll move it outside the if statement.

From developer.mozilla.org:

If initialValue is not specified, accumulator is initialized to the first value in the array, and callbackFn starts executing with the second value in the array as currentValue.

which clearly doesn't make sense in this situation. So it'll need to be init'd.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added a utility for array typing.


@HostBinding('class._fullWidth') get _() {
return this.fullWidth;
private renderError = (e: FormValidationError) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Misleading name, this doesnt render anything, but it sets the error object on a formControl

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed!

@wouter-willems wouter-willems merged commit 64afcf4 into main Oct 11, 2023
1 check passed
@wouter-willems
Copy link
Member

@olistrik @jerbob92 merged

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants