GithubHelp home page GithubHelp logo

Comments (4)

saheel-ahmed avatar saheel-ahmed commented on June 11, 2024

I have used this module in AngularJS and it works awesome and I have used more than 10 projects.

I have now requirement for Angular5 implementation so I was think to use this module. What is the best way to use it? Alternatively I'm thinking to go ng2-validation package. But I love this module.

from angular-auto-validate.

jonsamwell avatar jonsamwell commented on June 11, 2024

@saheel-ahmed I haven't got around to porting this to angular 5 yet. However, it is pretty easy to do with a directive and using the mat-error element from angular material. Basic code is below. If I get some time I might try and port this over. Contribution are welcome!

export abstract class ValidationDecoratorDirectiveBase implements Validator, OnChanges, OnDestroy, OnInit {
  @Input()
  public ngModel: any;
  @Input()
  public errorContainerId: string;  // the id of the mat-error element
  @Input()
  public preValidate: boolean = false;
  @Input()
  public getValidationErrorMessage: (errors: ValidationErrors) => string;
  @Input()
  public scrollIntoViewWhenInvalid: boolean = false;

  private statusChangeSubscription: Subscription;

  public constructor(protected parentForm: NgForm,
                     protected ngControl: NgControl,
                     protected element: ElementRef,
                     protected renderer: Renderer2,
                     protected utilService: UtilService,
                     protected validationMessageService: ValidationMessageService) {}

  @HostListener("blur")
  public onElementBlurred(markAsTouched: boolean = false): void {
    if (document.activeElement !== this.element.nativeElement) {
      if (this.canMarkInValid()) {
        this.markAsTouched();
        const primaryErrorKey = this.getFirstErrorKey(this.ngControl.errors);
        const remoteErrors = this.getRemoteErrors(this.ngControl.errors);
        let errorMessage = this.element.nativeElement.validationMessage ||
                           this.validationMessageService.getErrorMessage(primaryErrorKey,
                                                                         this.ngControl.errors[primaryErrorKey] ?
                                                                         this.ngControl.errors[primaryErrorKey].data ||
                                                                         this.ngControl.errors[primaryErrorKey] :
                                                                         undefined);
        if (remoteErrors.length > 0) {
          errorMessage = remoteErrors[0].message;
        }
        if (this.getValidationErrorMessage !== undefined) {
          errorMessage = this.getValidationErrorMessage(this.ngControl.errors) || errorMessage;
        }
        setTimeout(() => {
          const el = this.getErrorElement();
          this.makeInvalid(el, errorMessage);
          if (this.scrollIntoViewWhenInvalid && el.scrollIntoView) {
            el.scrollIntoView();
          }
        }, 100);
      } else if (this.canMarkValid()) {
        setTimeout(() => {
          this.markAsTouched();
          this.makeValid();
        }, 100);
      }
    }
  }

  public markAsTouched(): void {
    const formControl = this.parentForm.controls[this.ngControl.name] ||
                        this.parentForm.controls[this.errorContainerId];
    if (!this.ngControl.touched && formControl) {
      formControl.markAsTouched();
    }
  }

  public ngOnInit(): void {
    this.statusChangeSubscription = this.ngControl
                                        .statusChanges
                                        .subscribe((status) => {
                                            if (status === "INVALID") {
                                              this.onFormSubmitHandler(false);
                                            } else if (status === "VALID") {
                                              setTimeout(() => this.makeValid(), 100);
                                            }
                                          });
    this.parentForm.ngSubmit.subscribe((evt) => {
      this.onFormSubmitHandler(true);
    });
  }

  public ngOnChanges(changes: SimpleChanges): void {
    let change = changes.ngModel;
    if (!this.utilService.isNullOrUndefined(change) &&
        this.utilService.isNullOrUndefined(change.previousValue) &&
        !this.utilService.isNullOrUndefinedOrEmpty(change.currentValue)) {
      setTimeout(() => this.onElementBlurred(true), 100);
    }
  }

 public validate(control: AbstractControl): ValidationErrors|null  {
   return null;
  }

  public ngOnDestroy(): void {
    if (this.statusChangeSubscription) {
      this.statusChangeSubscription.unsubscribe();
    }
  }

  // tslint:disable-next-line:no-empty
  public registerOnValidatorChange(fn: () => void): void {}

  protected canMarkInValid(): boolean {
    let canValidate = false;
    const controlValue = this.ngControl.value;
    const isTouched = this.ngControl.touched;
    if (this.ngControl.invalid) {
      canValidate = isTouched || !this.utilService.isNullOrUndefinedOrEmpty(controlValue) ||
                    (this.preValidate);
    }
    return canValidate;
  }

  protected canMarkValid(): boolean {
    let canValidate = false;
    const controlValue = this.ngControl.value;
    const isTouched = this.ngControl.touched;
    if (this.ngControl.valid) {
      canValidate = (isTouched && !this.utilService.isNullOrUndefinedOrEmpty(controlValue)) ||
                    (this.preValidate && !this.utilService.isNullOrUndefinedOrEmpty(controlValue));
    }
    return canValidate;
  }

  protected getErrorElement(): HTMLElement {
    return document.getElementById(this.errorContainerId);
  }

  protected abstract makeInvalid(errorElement: HTMLElement, errorMessage: string): void;
  protected abstract makeValid(): void;

  private onFormSubmitHandler(markAsTouched = false): void {
    if (this.ngControl.invalid) {
      if (markAsTouched) {
        this.markAsTouched();
      }
      this.onElementBlurred(markAsTouched);
    }
  }

  private getRemoteErrors(errors: ValidationErrors): IRemoteValidationError[] {
    let remoteErrors: IRemoteValidationError[] = new Array<IRemoteValidationError>();
    for (let key in errors) {
      if (errors.hasOwnProperty(key) && errors[key].remote === true) {
        remoteErrors.push({ propertyName: errors[key].propertyName, message: errors[key].message, level: 1 });
      }
    }
    return remoteErrors;
  }

  private getFirstErrorKey(errors: ValidationErrors): string {
    const properties = Object.keys(errors).sort();
    return properties[0];
  }
}

// tslint:disable-next-line:max-classes-per-file
@Directive({
  selector: "[inputValidationDecorator]"
})
export class InputValidationDecoratorDirective extends ValidationDecoratorDirectiveBase {
  public constructor(@Host() parentForm: NgForm,
                     @Host() private parentContainer: MatFormField,
                     ngControl: NgControl,
                     element: ElementRef,
                     renderer: Renderer2,
                     utilService: UtilService,
                     validationMessageService: ValidationMessageService) {
    super(parentForm, ngControl, element, renderer, utilService, validationMessageService);
  }

  protected makeInvalid(errorElement: HTMLElement, errorMessage: string): void {
    if (!this.utilService.isNullOrUndefined(errorElement)) {
      errorElement.innerText = errorMessage;
    }
  }

  protected makeValid(): void {
    if (this.ngControl.touched) {
      this.renderer.addClass(this.parentContainer._elementRef.nativeElement, "mat-focused");
    }
  }
}

You would then use it like this:

       <mat-form-field>
          <input name="EmailAddress"
                type="email"
                placeholder="Email Address (optional)"
                [(ngModel)]="worker.emailAddress"
                matInput
                minLength="1"
                inputValidationDecorator errorContainerId="mdErrorEmail" [preValidate]="inEditMode">
          <mat-error id="mdErrorEmail"></mat-error>
        </mat-form-field>

I hope this helps

Thanks,

Jon

from angular-auto-validate.

saheel-ahmed avatar saheel-ahmed commented on June 11, 2024

Awesome 👍

Thank you, Jon. As I was using Bootstrap 4 with Angular 5, and this "inputValidationDecorator " concept should work.

from angular-auto-validate.

gconey avatar gconey commented on June 11, 2024

Inspired by your AngularJS version and using the above code as a starting point I created an couple of Angular directives that work well together to standardise and simplify form validation. They are built to work in the ASP.NET Zero Framework but could easily be adapted for general use. You'd need to implement the localizationservice yourself as it is something that's built into the framework.
See https://github.com/gconey/aspnet-zero-core-auto-validate

from angular-auto-validate.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.