UNPKG

@rx-signals/angular-provider

Version:
109 lines 13.8 kB
import { Directive, HostListener, Input, Output } from '@angular/core'; import { isValidModelValidationResult } from '@rx-signals/store'; import { BehaviorSubject, first } from 'rxjs'; import * as i0 from "@angular/core"; /** * Use this directive to couple a validation result `VR` for a certain property with the corresponding * isValid-status and the hasFocus- and touched-status of the corresponding control. * The isValid-status is determined using `isValidModelValidationResult()` from rx-signals/store. * E.g. given a model `type Model = { name: 'string'; };` you might have the following control (showing * only the attributes/properties relevant to this example): * ```ts * <div> * <label for="name">Name</label> * <input * id="name" * [rxsValidation]="model.validation | pick : 'name'" * #nameValidation="rxsValidation" * /> * </div> * <ng-container *ngIf="nameValidation.rxsValidationState | async as validation"> * <div *ngIf="!validation.valid && validation.touched" class="error"> * {{ validation.value }} * </div> * </ng-container> * </div> * ``` * * Analogously to standard Angular forms, this directive will set classes `ng-touched`, `ng-untouched`, `ng-valid` and `ng-invalid` * (it will not set classes for pristine- or dirty-status. cause these are attributes you can derive from your model behaviors) */ export class RxsValidationDirective { set rxsValidation(validationResult) { this.valid = isValidModelValidationResult(validationResult); this.value = validationResult; this.update(); } constructor(el, renderer) { this.el = el; this.renderer = renderer; this.validationState$ = new BehaviorSubject({ value: undefined, valid: false, hasFocus: false, touched: false, }); this.hasFocus = false; this.touched = false; this.value = undefined; this.valid = false; this.rxsValidationState = this.validationState$.asObservable(); this.update(); } onGotFocus() { this.hasFocus = true; this.touched = true; this.update(); } update() { this.validationState$.pipe(first()).subscribe(state => { if (this.touched && state.touched !== this.touched) { this.renderer.removeClass(this.el.nativeElement, 'ng-untouched'); this.renderer.addClass(this.el.nativeElement, 'ng-touched'); } else if (!state.touched) { this.renderer.addClass(this.el.nativeElement, 'ng-untouched'); } if (state.valid !== this.valid) { if (this.valid) { this.renderer.removeClass(this.el.nativeElement, 'ng-invalid'); this.renderer.addClass(this.el.nativeElement, 'ng-valid'); } else { this.renderer.removeClass(this.el.nativeElement, 'ng-valid'); this.renderer.addClass(this.el.nativeElement, 'ng-invalid'); } } if (state.touched !== this.touched || state.valid !== this.valid || state.hasFocus !== this.hasFocus || state.value !== this.value) { this.validationState$.next({ touched: this.touched, hasFocus: this.hasFocus, valid: this.valid, value: this.value, }); } }); } } RxsValidationDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.1.5", ngImport: i0, type: RxsValidationDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive }); RxsValidationDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.1.5", type: RxsValidationDirective, isStandalone: true, selector: "[rxsValidation]", inputs: { rxsValidation: "rxsValidation" }, outputs: { rxsValidationState: "rxsValidationState" }, host: { listeners: { "focusin": "onGotFocus()" } }, exportAs: ["rxsValidation"], ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.5", ngImport: i0, type: RxsValidationDirective, decorators: [{ type: Directive, args: [{ // eslint-disable-next-line @angular-eslint/directive-selector selector: '[rxsValidation]', exportAs: 'rxsValidation', standalone: true, }] }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.Renderer2 }]; }, propDecorators: { rxsValidation: [{ type: Input }], rxsValidationState: [{ type: Output }], onGotFocus: [{ type: HostListener, args: ['focusin'] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnhzLXZhbGlkYXRpb24uZGlyZWN0aXZlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvcngtc2lnbmFscy9hbmd1bGFyLXByb3ZpZGVyL3NyYy9saWIvZGlyZWN0aXZlcy9yeHMtdmFsaWRhdGlvbi5kaXJlY3RpdmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBYyxZQUFZLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBYSxNQUFNLGVBQWUsQ0FBQztBQUM5RixPQUFPLEVBQUUsNEJBQTRCLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUNqRSxPQUFPLEVBQUUsZUFBZSxFQUFFLEtBQUssRUFBRSxNQUFNLE1BQU0sQ0FBQzs7QUFTOUM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0F5Qkc7QUFPSCxNQUFNLE9BQU8sc0JBQXNCO0lBWWpDLElBQWEsYUFBYSxDQUFDLGdCQUFvQjtRQUM3QyxJQUFJLENBQUMsS0FBSyxHQUFHLDRCQUE0QixDQUFDLGdCQUFnQixDQUFDLENBQUM7UUFDNUQsSUFBSSxDQUFDLEtBQUssR0FBRyxnQkFBZ0IsQ0FBQztRQUM5QixJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7SUFDaEIsQ0FBQztJQUlELFlBQW9CLEVBQWMsRUFBVSxRQUFtQjtRQUEzQyxPQUFFLEdBQUYsRUFBRSxDQUFZO1FBQVUsYUFBUSxHQUFSLFFBQVEsQ0FBVztRQW5CdkQscUJBQWdCLEdBQUcsSUFBSSxlQUFlLENBQXNCO1lBQ2xFLEtBQUssRUFBRSxTQUFTO1lBQ2hCLEtBQUssRUFBRSxLQUFLO1lBQ1osUUFBUSxFQUFFLEtBQUs7WUFDZixPQUFPLEVBQUUsS0FBSztTQUNmLENBQUMsQ0FBQztRQUNLLGFBQVEsR0FBRyxLQUFLLENBQUM7UUFDakIsWUFBTyxHQUFHLEtBQUssQ0FBQztRQUNoQixVQUFLLEdBQW1CLFNBQVMsQ0FBQztRQUNsQyxVQUFLLEdBQUcsS0FB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aXN0ZW5lciwgSW5wdXQsIE91dHB1dCwgUmVuZGVyZXIyIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBpc1ZhbGlkTW9kZWxWYWxpZGF0aW9uUmVzdWx0IH0gZnJvbSAnQHJ4LXNpZ25hbHMvc3RvcmUnO1xuaW1wb3J0IHsgQmVoYXZpb3JTdWJqZWN0LCBmaXJzdCB9IGZyb20gJ3J4anMnO1xuXG5leHBvcnQgdHlwZSBWYWxpZGF0aW9uU3RhdGU8VlI+ID0ge1xuICB2YWx1ZTogVlIgfCB1bmRlZmluZWQ7XG4gIHZhbGlkOiBib29sZWFuO1xuICBoYXNGb2N1czogYm9vbGVhbjtcbiAgdG91Y2hlZDogYm9vbGVhbjtcbn07XG5cbi8qKlxuICogVXNlIHRoaXMgZGlyZWN0aXZlIHRvIGNvdXBsZSBhIHZhbGlkYXRpb24gcmVzdWx0IGBWUmAgZm9yIGEgY2VydGFpbiBwcm9wZXJ0eSB3aXRoIHRoZSBjb3JyZXNwb25kaW5nXG4gKiBpc1ZhbGlkLXN0YXR1cyBhbmQgdGhlIGhhc0ZvY3VzLSBhbmQgdG91Y2hlZC1zdGF0dXMgb2YgdGhlIGNvcnJlc3BvbmRpbmcgY29udHJvbC5cbiAqIFRoZSBpc1ZhbGlkLXN0YXR1cyBpcyBkZXRlcm1pbmVkIHVzaW5nIGBpc1ZhbGlkTW9kZWxWYWxpZGF0aW9uUmVzdWx0KClgIGZyb20gcngtc2lnbmFscy9zdG9yZS5cbiAqIEUuZy4gZ2l2ZW4gYSBtb2RlbCBgdHlwZSBNb2RlbCA9IHsgbmFtZTogJ3N0cmluZyc7IH07YCB5b3UgbWlnaHQgaGF2ZSB0aGUgZm9sbG93aW5nIGNvbnRyb2wgKHNob3dpbmdcbiAqIG9ubHkgdGhlIGF0dHJpYnV0ZXMvcHJvcGVydGllcyByZWxldmFudCB0byB0aGlzIGV4YW1wbGUpOlxuICogYGBgdHNcbiAqIDxkaXY+XG4gKiAgIDxsYWJlbCBmb3I9XCJuYW1lXCI+TmFtZTwvbGFiZWw+XG4gKiAgICAgPGlucHV0XG4gKiAgICAgICBpZD1cIm5hbWVcIlxuICogICAgICAgW3J4c1ZhbGlkYXRpb25dPVwibW9kZWwudmFsaWRhdGlvbiB8IHBpY2sgOiAnbmFtZSdcIlxuICogICAgICAgI25hbWVWYWxpZGF0aW9uPVwicnhzVmFsaWRhdGlvblwiXG4gKiAgICAgLz5cbiAqICAgICA8L2Rpdj5cbiAqICAgICA8bmctY29udGFpbmVyICpuZ0lmPVwibmFtZVZhbGlkYXRpb24ucnhzVmFsaWRhdGlvblN0YXRlIHwgYXN5bmMgYXMgdmFsaWRhdGlvblwiPlxuICogICAgICAgPGRpdiAqbmdJZj1cIiF2YWxpZGF0aW9uLnZhbGlkICYmIHZhbGlkYXRpb24udG91Y2hlZFwiIGNsYXNzPVwiZXJyb3JcIj5cbiAqICAgICAgICAge3sgdmFsaWRhdGlvbi52YWx1ZSB9fVxuICogICAgICAgPC9kaXY+XG4gKiAgICAgPC9uZy1jb250YWluZXI+XG4gKiA8L2Rpdj5cbiAqIGBgYFxuICpcbiAqIEFuYWxvZ291c2x5IHRvIHN0YW5kYXJkIEFuZ3VsYXIgZm9ybXMsIHRoaXMgZGlyZWN0aXZlIHdpbGwgc2V0IGNsYXNzZXMgYG5nLXRvdWNoZWRgLCBgbmctdW50b3VjaGVkYCwgYG5nLXZhbGlkYCBhbmQgYG5nLWludmFsaWRgXG4gKiAoaXQgd2lsbCBub3Qgc2V0IGNsYXNzZXMgZm9yIHByaXN0aW5lLSBvciBkaXJ0eS1zdGF0dXMuIGNhdXNlIHRoZXNlIGFyZSBhdHRyaWJ1dGVzIHlvdSBjYW4gZGVyaXZlIGZyb20geW91ciBtb2RlbCBiZWhhdmlvcnMpXG4gKi9cbkBEaXJlY3RpdmUoe1xuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQGFuZ3VsYXItZXNsaW50L2RpcmVjdGl2ZS1zZWxlY3RvclxuICBzZWxlY3RvcjogJ1tyeHNWYWxpZGF0aW9uXScsXG4gIGV4cG9ydEFzOiAncnhzVmFsaWRhdGlvbicsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG59KVxuZXhwb3J0IGNsYXNzIFJ4c1ZhbGlkYXRpb25EaXJlY3RpdmU8VlI+IHtcbiAgcHJpdmF0ZSB2YWxpZGF0aW9uU3RhdGUkID0gbmV3IEJlaGF2aW9yU3ViamVjdDxWYWxpZGF0aW9uU3RhdGU8VlI+Pih7XG4gICAgdmFsdWU6IHVuZGVmaW5lZCxcbiAgICB2YWxpZDogZmFsc2UsXG4gICAgaGFzRm9jdXM6IGZhbHNlLFxuICAgIHRvdWNoZWQ6IGZhbHNlLFxuICB9KTtcbiAgcHJpdmF0ZSBoYXNGb2N1cyA9IGZhbHNlO1xuICBwcml2YXRlIHRvdWNoZWQgPSBmYWxzZTtcbiAgcHJpdmF0ZSB2YWx1ZTogVlIgfCB1bmRlZmluZWQgPSB1bmRlZmluZWQ7XG4gIHByaXZhdGUgdmFsaWQgPSBmYWxzZTtcblxuICBASW5wdXQoKSBzZXQgcnhzVmFsaWRhdGlvbih2YWxpZGF0aW9uUmVzdWx0OiBWUikge1xuICAgIHRoaXMudmFsaWQgPSBpc1ZhbGlkTW9kZWxWYWxpZGF0aW9uUmVzdWx0KHZhbGlkYXRpb25SZXN1bHQpO1xuICAgIHRoaXMudmFsdWUgPSB2YWxpZGF0aW9uUmVzdWx0O1xuICAgIHRoaXMudXBkYXRlKCk7XG4gIH1cblxuICBAT3V0cHV0KCkgcmVhZG9ubHkgcnhzVmFsaWRhdGlvblN0YXRlID0gdGhpcy52YWxpZGF0aW9uU3RhdGUkLmFzT2JzZXJ2YWJsZSgpO1xuXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgZWw6IEVsZW1lbnRSZWYsIHByaXZhdGUgcmVuZGVyZXI6IFJlbmRlcmVyMikge1xuICAgIHRoaXMudXBkYXRlKCk7XG4gIH1cblxuICBASG9zdExpc3RlbmVyKCdmb2N1c2luJylcbiAgcHJvdGVjdGVkIG9uR290Rm9jdXMoKTogdm9pZCB7XG4gICAgdGhpcy5oYXNGb2N1cyA9IHRydWU7XG4gICAgdGhpcy50b3VjaGVkID0gdHJ1ZTtcbiAgICB0aGlzLnVwZGF0ZSgpO1xuICB9XG5cbiAgcHJpdmF0ZSB1cGRhdGUoKSB7XG4gICAgdGhpcy52YWxpZGF0aW9uU3RhdGUkLnBpcGUoZmlyc3QoKSkuc3Vic2NyaWJlKHN0YXRlID0+IHtcbiAgICAgIGlmICh0aGlzLnRvdWNoZWQgJiYgc3RhdGUudG91Y2hlZCAhPT0gdGhpcy50b3VjaGVkKSB7XG4gICAgICAgIHRoaXMucmVuZGVyZXIucmVtb3ZlQ2xhc3ModGhpcy5lbC5uYXRpdmVFbGVtZW50LCAnbmctdW50b3VjaGVkJyk7XG4gICAgICAgIHRoaXMucmVuZGVyZXIuYWRkQ2xhc3ModGhpcy5lbC5uYXRpdmVFbGVtZW50LCAnbmctdG91Y2hlZCcpO1xuICAgICAgfSBlbHNlIGlmICghc3RhdGUudG91Y2hlZCkge1xuICAgICAgICB0aGlzLnJlbmRlcmVyLmFkZENsYXNzKHRoaXMuZWwubmF0aXZlRWxlbWVudCwgJ25nLXVudG91Y2hlZCcpO1xuICAgICAgfVxuICAgICAgaWYgKHN0YXRlLnZhbGlkICE9PSB0aGlzLnZhbGlkKSB7XG4gICAgICAgIGlmICh0aGlzLnZhbGlkKSB7XG4gICAgICAgICAgdGhpcy5yZW5kZXJlci5yZW1vdmVDbGFzcyh0aGlzLmVsLm5hdGl2ZUVsZW1lbnQsICduZy1pbnZhbGlkJyk7XG4gICAgICAgICAgdGhpcy5yZW5kZXJlci5hZGRDbGFzcyh0aGlzLmVsLm5hdGl2ZUVsZW1lbnQsICduZy12YWxpZCcpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRoaXMucmVuZGVyZXIucmVtb3ZlQ2xhc3ModGhpcy5lbC5uYXRpdmVFbGVtZW50LCAnbmctdmFsaWQnKTtcbiAgICAgICAgICB0aGlzLnJlbmRlcmVyLmFkZENsYXNzKHRoaXMuZWwubmF0aXZlRWxlbWVudCwgJ25nLWludmFsaWQnKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgaWYgKFxuICAgICAgICBzdGF0ZS50b3VjaGVkICE9PSB0aGlzLnRvdWNoZWQgfHxcbiAgICAgICAgc3RhdGUudmFsaWQgIT09IHRoaXMudmFsaWQgfHxcbiAgICAgICAgc3RhdGUuaGFzRm9jdXMgIT09IHRoaXMuaGFzRm9jdXMgfHxcbiAgICAgICAgc3RhdGUudmFsdWUgIT09IHRoaXMudmFsdWVcbiAgICAgICkge1xuICAgICAgICB0aGlzLnZhbGlkYXRpb25TdGF0ZSQubmV4dCh7XG4gICAgICAgICAgdG91Y2hlZDogdGhpcy50b3VjaGVkLFxuICAgICAgICAgIGhhc0ZvY3VzOiB0aGlzLmhhc0ZvY3VzLFxuICAgICAgICAgIHZhbGlkOiB0aGlzLnZhbGlkLFxuICAgICAgICAgIHZhbHVlOiB0aGlzLnZhbHVlLFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxufVxuIl19