From 7021a3a5f677c21d962817227c202b9ea517fe6a Mon Sep 17 00:00:00 2001 From: Helias Date: Thu, 23 Jan 2025 12:15:52 +0100 Subject: [PATCH] refactor(validate-input.directive.ts): rewrite directive making it agnostic --- .../creature-template.component.html | 9 +--- .../creature-template.component.ts | 6 +-- .../src/validate-input.directive.ts | 45 ++++++++++++++----- libs/shared/error-templates/.eslintrc.json | 33 -------------- libs/shared/error-templates/README.md | 3 -- libs/shared/error-templates/karma.conf.js | 15 ------- libs/shared/error-templates/project.json | 24 ---------- libs/shared/error-templates/src/index.ts | 1 - .../src/input-validation-error.ts | 24 ---------- libs/shared/error-templates/tsconfig.json | 29 ------------ libs/shared/error-templates/tsconfig.lib.json | 12 ----- .../shared/error-templates/tsconfig.spec.json | 9 ---- 12 files changed, 38 insertions(+), 172 deletions(-) delete mode 100644 libs/shared/error-templates/.eslintrc.json delete mode 100644 libs/shared/error-templates/README.md delete mode 100644 libs/shared/error-templates/karma.conf.js delete mode 100644 libs/shared/error-templates/project.json delete mode 100644 libs/shared/error-templates/src/index.ts delete mode 100644 libs/shared/error-templates/src/input-validation-error.ts delete mode 100644 libs/shared/error-templates/tsconfig.json delete mode 100644 libs/shared/error-templates/tsconfig.lib.json delete mode 100644 libs/shared/error-templates/tsconfig.spec.json diff --git a/libs/features/creature/src/creature-template/creature-template.component.html b/libs/features/creature/src/creature-template/creature-template.component.html index 36989f8c6ee..9fbb099c500 100644 --- a/libs/features/creature/src/creature-template/creature-template.component.html +++ b/libs/features/creature/src/creature-template/creature-template.component.html @@ -48,14 +48,7 @@
- - +
diff --git a/libs/features/creature/src/creature-template/creature-template.component.ts b/libs/features/creature/src/creature-template/creature-template.component.ts index 23108297dba..107ea80b0e5 100644 --- a/libs/features/creature/src/creature-template/creature-template.component.ts +++ b/libs/features/creature/src/creature-template/creature-template.component.ts @@ -1,5 +1,6 @@ import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { RouterLink } from '@angular/router'; import { CREATURE_AI_NAME, CREATURE_CLASS, @@ -25,6 +26,7 @@ import { } from '@keira/shared/acore-world-model'; import { SingleRowEditorComponent } from '@keira/shared/base-abstract-classes'; import { QueryOutputComponent, TopBarComponent } from '@keira/shared/base-editor-components'; +import { InputValidationDirective } from '@keira/shared/directives'; import { BooleanOptionSelectorComponent, CreatureSelectorBtnComponent, @@ -39,9 +41,6 @@ import { TranslateModule } from '@ngx-translate/core'; import { TooltipModule } from 'ngx-bootstrap/tooltip'; import { CreatureHandlerService } from '../creature-handler.service'; import { CreatureTemplateService } from './creature-template.service'; -import { RouterLink } from '@angular/router'; -import { InputValidationDirective } from '@keira/shared/directives'; -import { ValidationFeedbackComponent } from '@keira/shared/error-templates'; @Component({ changeDetection: ChangeDetectionStrategy.OnPush, @@ -65,7 +64,6 @@ import { ValidationFeedbackComponent } from '@keira/shared/error-templates'; IconSelectorComponent, RouterLink, InputValidationDirective, - ValidationFeedbackComponent, ], }) export class CreatureTemplateComponent extends SingleRowEditorComponent { diff --git a/libs/shared/directives/src/validate-input.directive.ts b/libs/shared/directives/src/validate-input.directive.ts index e4af19476d8..19dabf12ebe 100644 --- a/libs/shared/directives/src/validate-input.directive.ts +++ b/libs/shared/directives/src/validate-input.directive.ts @@ -1,24 +1,49 @@ -import { Directive, ElementRef, HostBinding, Input, OnInit } from '@angular/core'; -import { AbstractControl } from '@angular/forms'; +import { Directive, ElementRef, inject, OnInit, Renderer2 } from '@angular/core'; +import { AbstractControl, NgControl } from '@angular/forms'; +import { SubscriptionHandler } from '@keira/shared/utils'; @Directive({ selector: '[keiraInputValidation]', standalone: true, }) -export class InputValidationDirective implements OnInit { - @Input('keiraInputValidation') control!: AbstractControl | null; +export class InputValidationDirective extends SubscriptionHandler implements OnInit { + private readonly el: ElementRef = inject(ElementRef); + private readonly renderer: Renderer2 = inject(Renderer2); + private readonly ngControl: NgControl = inject(NgControl); - constructor(private el: ElementRef) {} + private errorDiv: HTMLElement | null = null; ngOnInit(): void { - if (!this.control) { - console.warn('ValidationDirective: No control provided.'); + const control = this.ngControl.control; + + if (!control) { return; } + + this.subscriptions.push( + control.statusChanges?.subscribe(() => { + this.updateErrorMessage(control); + }), + ); } - @HostBinding('class.is-invalid') - get isInvalid(): boolean { - return !!this.control?.invalid && !!this.control?.touched; + private updateErrorMessage(control: AbstractControl): void { + if (this.errorDiv) { + this.renderer.removeChild(this.el.nativeElement.parentNode, this.errorDiv); + this.errorDiv = null; + } + + if (control?.touched && control?.invalid) { + this.errorDiv = this.renderer.createElement('div'); + this.renderer.addClass(this.errorDiv, 'error-message'); + + const errorMessage = control?.errors?.['required'] ? 'This field is required' : 'Invalid field'; + + const text = this.renderer.createText(errorMessage); + this.renderer.appendChild(this.errorDiv, text); + + const parent = this.el.nativeElement.parentNode; + this.renderer.appendChild(parent, this.errorDiv); + } } } diff --git a/libs/shared/error-templates/.eslintrc.json b/libs/shared/error-templates/.eslintrc.json deleted file mode 100644 index a20cf65c221..00000000000 --- a/libs/shared/error-templates/.eslintrc.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "extends": ["../../../.eslintrc.json"], - "ignorePatterns": ["!**/*"], - "overrides": [ - { - "files": ["*.ts"], - "extends": ["plugin:@nx/angular", "plugin:@angular-eslint/template/process-inline-templates"], - "rules": { - "@angular-eslint/directive-selector": [ - "error", - { - "type": "attribute", - "prefix": "keira", - "style": "camelCase" - } - ], - "@angular-eslint/component-selector": [ - "error", - { - "type": "element", - "prefix": "keira", - "style": "kebab-case" - } - ] - } - }, - { - "files": ["*.html"], - "extends": ["plugin:@nx/angular-template"], - "rules": {} - } - ] -} diff --git a/libs/shared/error-templates/README.md b/libs/shared/error-templates/README.md deleted file mode 100644 index 4a2b5d63f79..00000000000 --- a/libs/shared/error-templates/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# error-templates - -This library was generated with [Nx](https://nx.dev). diff --git a/libs/shared/error-templates/karma.conf.js b/libs/shared/error-templates/karma.conf.js deleted file mode 100644 index c8eb83219f9..00000000000 --- a/libs/shared/error-templates/karma.conf.js +++ /dev/null @@ -1,15 +0,0 @@ -const { join } = require('path'); -const getBaseKarmaConfig = require('../../../karma.conf'); - -module.exports = function (config) { - const baseConfig = getBaseKarmaConfig(config); - config.set({ - ...baseConfig, - frameworks: [...baseConfig.frameworks], - plugins: [...baseConfig.plugins], - coverageReporter: { - ...baseConfig.coverageReporter, - dir: join(__dirname, '../../../coverage/libs/shared/error-templates'), - }, - }); -}; diff --git a/libs/shared/error-templates/project.json b/libs/shared/error-templates/project.json deleted file mode 100644 index 15ad7f284ab..00000000000 --- a/libs/shared/error-templates/project.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "keira-shared-error-templates", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "sourceRoot": "libs/shared/error-templates/src", - "prefix": "keira", - "tags": ["scope:shared"], - "projectType": "library", - "targets": { - "test": { - "executor": "@angular-devkit/build-angular:karma", - "options": { - "tsConfig": "libs/shared/error-templates/tsconfig.spec.json", - "karmaConfig": "libs/shared/error-templates/karma.conf.js", - "polyfills": ["zone.js", "zone.js/testing"], - "sourceMap": true, - "codeCoverage": true, - "scripts": [] - } - }, - "lint": { - "executor": "@nx/eslint:lint" - } - } -} diff --git a/libs/shared/error-templates/src/index.ts b/libs/shared/error-templates/src/index.ts deleted file mode 100644 index 42da3af9086..00000000000 --- a/libs/shared/error-templates/src/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './input-validation-error'; diff --git a/libs/shared/error-templates/src/input-validation-error.ts b/libs/shared/error-templates/src/input-validation-error.ts deleted file mode 100644 index 43c648bb2c9..00000000000 --- a/libs/shared/error-templates/src/input-validation-error.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Component, Input } from '@angular/core'; -import { AbstractControl } from '@angular/forms'; - -@Component({ - selector: 'keira-validation-feedback', - standalone: true, - template: ` - @if (control?.invalid && control?.touched) { -
- {{ errorMessage }} -
- } - `, -}) -export class ValidationFeedbackComponent { - @Input() control!: AbstractControl | null; - - get errorMessage(): string { - if (this.control?.errors?.['required']) { - return 'This field is required'; - } - return 'Invalid field'; - } -} diff --git a/libs/shared/error-templates/tsconfig.json b/libs/shared/error-templates/tsconfig.json deleted file mode 100644 index 5cf0a165647..00000000000 --- a/libs/shared/error-templates/tsconfig.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "target": "es2022", - "useDefineForClassFields": false, - "forceConsistentCasingInFileNames": true, - "strict": true, - "noImplicitOverride": true, - "noPropertyAccessFromIndexSignature": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true - }, - "files": [], - "include": [], - "references": [ - { - "path": "./tsconfig.lib.json" - }, - { - "path": "./tsconfig.spec.json" - } - ], - "extends": "../../../tsconfig.base.json", - "angularCompilerOptions": { - "enableI18nLegacyMessageIdFormat": false, - "strictInjectionParameters": true, - "strictInputAccessModifiers": true, - "strictTemplates": true - } -} diff --git a/libs/shared/error-templates/tsconfig.lib.json b/libs/shared/error-templates/tsconfig.lib.json deleted file mode 100644 index f68063a5171..00000000000 --- a/libs/shared/error-templates/tsconfig.lib.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../../../dist/out-tsc", - "declaration": true, - "declarationMap": true, - "inlineSources": true, - "types": [] - }, - "exclude": ["src/**/*.spec.ts", "jest.config.ts", "src/**/*.test.ts"], - "include": ["src/**/*.ts"] -} diff --git a/libs/shared/error-templates/tsconfig.spec.json b/libs/shared/error-templates/tsconfig.spec.json deleted file mode 100644 index b864ec66ae9..00000000000 --- a/libs/shared/error-templates/tsconfig.spec.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../out-tsc/spec", - "types": ["jasmine", "node"] - }, - "include": ["**/*.spec.ts", "**/*.d.ts"], - "exclude": ["dist", "release", "node_modules"] -}