npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

ngx-common-forms

v0.5.0

Published

Forms are straight-forward... if user doesn't make any mistakes. Throw in all (client-side and server-side) the validation messages, the loading spinner, disable submission while the form is already submitting, and you end up with a huge pile of mess... i

Downloads

9

Readme

ngx-common-forms

Forms are straight-forward... if user doesn't make any mistakes. Throw in all (client-side and server-side) the validation messages, the loading spinner, disable submission while the form is already submitting, and you end up with a huge pile of mess... in every. single. form. again. and. again.

If you have a fairy common form, without some extremely crazy stuff, this package will handle all this for you, while still leaving enough room for customization. All while following regular Angular form-related principles.

Stack Blitz Demo

Installation

# with yarn
yarn add ngx-common-forms

# with npm
npm i ngx-common-forms

Feature highlights

  • Submitting an invalid form immediately triggers displaying declarative client-side validation.
  • If a server-side error occurs, the errors are automatically inserted to the form.
  • The first field marked as invalid will immediately receive focus to aid your users. (Also great for long forms as browsers will automatically scroll to the field.)
  • Leverage the "loading" observable to show a spinner in the submit button (or some other indicator).
  • While in loading state, form cannot be re-submitted.
  • Your API call is a simple function which takes the forum value and returns an observable. You can pass it in directly from your services.

Basic usage

Import the module

@NgModule({
  // ...
  imports: [
    // ...
    CommonFormModule.forRoot(),
    // ...
  ],
  // ...
})

Bind the API call to commonForm

// The good old service for trigger an endpoint

@Injectable()
export class ApiService {
  public logIn({ username, passowrd }): Observable<any> {
    return this.http.post(
      `https://api.example/log-in`,
      { username, password },
    );
  }
}
@Component({ /* ... */ })
export class MyComponent {
  constructor(private fb: FormBuilder,
              public api: ApiService) { // inject the service
  }
  
  // A regular reactive form, with regular validation messages.
  public form = this.fb.group({
    username: ['', [Validators.required]],
    password: ['', [Validators.required, Validators.minLength(6)]],
  });

  // Instead of `(ngSubmit)`, you listen to `(commonFormSubmit)` and react to form submission.
  // For example, you can redirect here or display a snackbar indicating success,
  // or further react to errors in submission.
  public onSubmit(response$: Observable<any>) {
    response$.subscribe(response => {
      console.log(response);
    });
  }
}
<form [formGroup]="form"
      [commonForm]="api.logIn.bind(api)"
      (commonFormSubmit)="onSubmit($event)"
>

  <label>
    <span>Username</span>
    <input type="text" formControlName="username">
  </label>
  <div sins="username">
    <!-- The library handles displaying these at the right time. -->
    <!-- All you have to do is type them out (and give them styles, animations, etc). -->
    <span *sin="'required'">Username is required.</span>
    <span *sin="'serverError' let msg">{{ msg }}</span>
  </div>
  
  <label>
    <span>Password</span>
    <input type="password" formControlName="password">
  </label>
  <div sins="password">
    <span *sin="'required'">Password is required.</span>
    <span *sin="'minlength'">Password must have at least 6 characters.</span>
    <span *sin="'serverError' let msg">{{ msg }}</span>
    <!-- If the server responds with an error, it will be added to form's errors under key "serverError". -->
    <!-- The exact message is also available via a simple binding, as above. -->  
  </div>

  <button type="submit">Log in</button>

</form>

Button spinner

See src/app/button.component.ts.

Finer configuration

Different apps will have different kinds of forms, but even more different kinds of APIs. Each team has established habits which they follow across every project. Hence, ngx-common-forms offers configuration settings to match your API.

The default configuration is supplied as an object to the forRoot method call when importing the module. Here's the typing information for this object.

export interface CommonFormConfigObject {
  propagateErrors?: boolean;
  transform?: CommonFormTransform;
  isValidationError?: CommonFormIsValidationError;
  transformError?: CommonFormTransformError;
  request?: CommonFormRequest;
}

export type CommonFormTransform = (formValue: any) => any;
export type CommonFormIsValidationError = (response: HttpErrorResponse) => boolean
export type CommonFormTransformError = (formValue: any) => FlatServerErrors;
export type CommonFormRequest<T = any> = (formValue: T) => Observable<T>;

export interface FlatServerErrors {
  [path: string]: string;
}

Each of these keys can also be configured individually on per-form basis, which allows you to overwrite these global settings in case some of the forms is one-of-a-kind.

Request

The request option doesn't make much sense to be configured globally, since it's the function which takes form value and returns an observable. Typically this is what you already have in your service methods.

For providing it as an input, you can use the [request] input. However, since this is the main which you always use, there's an alias [commonForm]. Since commonForm is also the name of the directive, you write it only once this way, saving keystrokes.

Transform

Before you send the form value to the server, you might want to transform it a bit. This can be done in the request function itself, but ngx-common-forms also allows you to provide a separate transforming function. Basically, this means that instead of request(formValue), the library does request(transform(formValue)).

Is validation error

Use isValidationError to pass in a predicate used to determine if the error which occurred during the request is supposed to be queried for validation errors inside. By default this checks for the 422 status in HTTP response.

This is how you tell the lib which type of error responses you consider "validation errors". For example, a 5xx and 4xx error should probably be handled differently.

A predicate is a function which returns boolean value.

Transform error

When the lib understands which types of errors should be treated as validation errors, it must also know how to interpret the payload from the response and apply it to the form (in order to show validation messages). transformError is a function which describes how the server response should be mapped to FlatServerErrors, which has a simple signature { [path: string]: string }.

Here's an example of a flat error.

{
  'username': 'Username must not contain spaces',
  'location': 'Invalid location, see details below',
  'location.zip': 'This field must contain a valid zip code',
}

Propagate errors

The propagateErrors is a boolean flag determining whether received error will be propagated, i.e. if the observable you receive from (commonFormSubmit) will throw with your server error. In most cases you do not need this as errors caught with isValidationError will be handled by the lib, but sometimes you might want to override it with custom logic tied too closely to the component.


Built with @angular/[email protected].