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

@marcura/dadesk-ui-form

v2.0.0

Published

Library which helps manage forms in an organized manner in DA-Desk projects.

Downloads

251

Readme

@marcura/dadesk-ui-form

Library which helps manage forms in an organized manner in DA-Desk projects.

This version is expected to work with Angular 15.x.

FormTools

A utility class for working with Angular forms. Provides static methods to handle form control states, values, and validators.

Form

The Form class is a comprehensive utility for managing form controls and their states. It provides methods to add, remove, attach, and detach controls, as well as to enable or disable them. The class also offers observables to track the state of the form and its controls.

In general, we have two main states of Control:

  • registered: control is known to the form, but may be not attached to the Angular FormGroup
  • attached: control is attached to the Angular FormGroup

So this way we have a Control's lifecycle like below:

  • creation
  • registration
  • attachment

With optional phases of:

  • detachment
  • unregistration

Once control is detached it can be attached again without knowing its' name, because it's still registered.

We have shortcuts performing more than one operation, which will be mostly used in common scenarios i.e.:

createControl() = creation + register() + attach():

public readonly name: Forms.Control<string> = this.createControl('name', '');`
  • addControl() = register() + attach()
public readonly age: Forms.Control<number | null> = this.addControl('age', new FormControl());`

But, if needed, we can perform each operation separately. I.e. we can register a control without attaching it to the form:

public readonly document: Forms.Control<string> = this.registerControl('document', nonNullControl(''));`

For adding subforms and form arrays, we have dedicated methods:

  • addForm()
  • addArray()

This class provides also setChildEnabled() and setChildDisabled() methods, which should be used to enable/disable controls with attaching/detaching them at the same time without a risk of accidental enabling of them while enabling the whole form.

export class PersonForm extends Form {
  public readonly name: FormControl<string> = this.createControl('name', '', Validators.required);
  public readonly age: FormControl<number> = this.createControl('age', 0, Validators.min(0));
  public readonly document: FormControl<string> = this.createControl('document', '');
  public readonly address: AddressForm = this.addForm('address', new AddressForm());
  public readonly books: FormArray<BookForm> = this.addArray('books', new FormArray());

  public readonly saveWorker: Worker = this.observer.add(new Worker());
  public readonly schema$: State<PersonSchema | null> = this.observer.add(new State<PersonSchema | null>(null));
  public readonly isSubmitDisabled$: Snapshot<boolean> = this.observer.add(
    Snapshot.from(false, Rx.atLeastOneIsTrue([this.isPending$, this.isDisabled$]))
  );

  public constructor() {
    super();
    this.listen(this.saveWorker.isWorking$, this.setDisabled);

    this.listen(FormTools.getValue$(this.age).pipe(map((age) => age >= 18)), (hasDocument) => {
      this.setChildEnabled(this.document)(hasDocument);
      FormTools.setValidators(this.document, hasDocument ? [Validators.required, Validators.minLength(3)] : null);
    });

    this.listen(this.schema$, (schema) => {
      this.name.setValue(schema?.name ?? '');
      this.age.setValue(schema?.age ?? 0);
      this.document.setValue(schema?.document ?? '');
      this.address.schema.set(schema?.address ?? null);
      this.books.updateItemsByValues({
        values: schema?.books ?? [],
        hasValue: (form, value) => form.schema.get()?.id === value.id,
        create: (value) => new BookForm(value),
        update: (form, value) => form.schema.set(value),
        destroy: (form) => form.destroy(),
      });
    });
  }

  public toSchema(): PersonSchema {
    return {
      id: this.schema$.get()?.id,
      name: this.name.value,
      age: this.age.value,
      document: this.document.value,
      address: this.address.toSchema(),
      books: this.books.items.map((form) => form.toSchema()),
    };
  }

  public addBook(): void {
    this.books.push(new BookForm());
  }

  public removeBook(book: BookForm): void {
    this.books.removeItem(book);
  }
}

FormControlArray

A specialized form array class that extends AbstractFormArray. This class is designed to handle an array of form controls of type TControl.

import {FormControlArray} from '@marcura/dadesk-ui-form';

const formArray: FormControlArray<FormControl<number>> = new FormControlArray<FormControl<number>>();
formArray.items$.subscribe((items) => console.log(items));
formArray.push(new FormControl(123));
formArray.removeAt(0);

FormArray

A specialized form array class that extends AbstractFormArray. This class is designed to handle an array of form groups of type TForm.

import {Form, FormArray} from '@marcura/dadesk-ui-form';

class MyForm extends Form {
  public readonly name: FormControl<string> = this.createControl('');
}

const formArray: FormArray<MyForm> = new FormArray<MyForm>();
formArray.items$.subscribe((items) => console.log(items));
formArray.push(new MyForm());
formArray.removeAt(0);

SubmittableForm

Represents a form that can be submitted and includes a worker to handle asynchronous tasks. Extends the base Form class.

FormService

Service to handle form-related operations such as validation and focus management.

FormService.validate<TForm extends Form>(form: TForm, scrollToInvalid: boolean = true): Promise<boolean>

Validates the form and returns whether it is valid. If any invalid control found, it automatically scrolls to it.

import {Form} from '@marcura/dadesk-ui-form';

const form = new Form();
form.addControl('name', new FormControl('', Validators.required));
form.addControl('email', new FormControl('', Validators.email));

const isValid: boolean = await formService.validate(form);
if (isValid) {
  console.log('Form is valid');
} else {
  console.log('Form is invalid');
}

FormService.requestFocus(control: NgAbstractControl)

Requests to focus on the specified control.

FormService.getInvalidControl(formGroup: NgFormGroup): AbstractControl | null

Returns the first invalid control in the form group. If no invalid control found, it returns null.

const form = new FormGroup({
  name: new FormControl('', Validators.required),
  email: new FormControl('', Validators.email),
});

const invalidControl: AbstractControl | null = formService.getInvalidControl(form);
if (invalidControl) {
  console.log('Invalid control found:', invalidControl);
} else {
  console.log('No invalid control found');
}