Skip to content

fix(tags): move validation to kbq-tag-list (#DS-2943) - #1977

Open
artembelik wants to merge 3 commits into
mainfrom
fix/DS-2943
Open

fix(tags): move validation to kbq-tag-list (#DS-2943)#1977
artembelik wants to merge 3 commits into
mainfrom
fix/DS-2943

Conversation

@artembelik

Copy link
Copy Markdown
Contributor

No description provided.

@artembelik artembelik self-assigned this Sep 2, 2026
Copilot AI lite review requested due to automatic review settings September 2, 2026 14:09
@artembelik artembelik added the bug Something isn't working label Sep 2, 2026
@artembelik artembelik changed the title Fix/ds 2943 fix(tags): stop bypassing validation on paste (#DS-2943) Sep 2, 2026
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown

Visit the preview URL for this PR (updated for commit 0237b43):

https://koobiq-next--prs-1977-znmhuue9.web.app

(expires Sun, 06 Sep 2026 14:41:08 GMT)

🔥 via Firebase Hosting GitHub Action 🌎

Sign: c9e37e518febda70d0317d07e8ceb35ac43c534c

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

KbqTagInput.ngControl is injected as optional but asserted non-null, creating an incorrect public/runtime contract that should be reconciled (and the API snapshot updated accordingly).

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR aligns tag creation behavior across typing/blur/paste so validation is consistently applied via the <kbq-tag-list> form control (instead of the input), and documents the recommended validation approach with updated examples.

Changes:

  • Refactors KbqTagInput to add tags through a single path for typing/blur/paste and removes validation gating based on an input-bound NgControl.
  • Deprecates the input-bound ngControl/triggerValidation() surface and updates docs to state validators must be attached to <kbq-tag-list>.
  • Adds/updates docs examples and expands unit tests to cover paste + validation + error-state behavior.
File summaries
File Description
tools/public_api_guard/components/tags.api.md Marks deprecated surfaces in extracted public API snapshot.
packages/docs-examples/example-module.ts Registers new docs examples and lazy-load switch cases.
packages/docs-examples/components/tags/tag-input-with-form-control-validators/tag-input-with-form-control-validators-example.ts Updates validation example to validate the tag array and improves UI messaging.
packages/docs-examples/components/tags/tag-autocomplete-with-form-control-validators/tag-autocomplete-with-form-control-validators-example.ts Adds a new autocomplete + validators example covering typed/pasted/selected tags.
packages/docs-examples/components/tags/index.ts Exports/registers the new validators example component.
packages/components/tags/tag-text-control.ts Documents the interface and deprecates ngControl in the contract.
packages/components/tags/tag-list.component.ts Removes legacy error-bridging from input control to list control.
packages/components/tags/tag-input.ts Unifies tag creation logic and stops blocking paste based on input validation.
packages/components/tags/tag-input.spec.ts Adds regression tests for paste empties + validation behavior + error state matchers.
packages/components/tags/tag-input.ru.md Documents validation model and updates embedded example reference (RU).
packages/components/tags/tag-input.en.md Documents validation model and updates embedded example reference (EN).
packages/components/tags/tag-autocomplete.ru.md Adds validation guidance and example reference (RU).
packages/components/tags/tag-autocomplete.en.md Adds validation guidance and example reference (EN).
packages/components/tags/examples.tag-input.ru.md Removes older embedded validation section in examples (RU).
packages/components/tags/examples.tag-input.en.md Removes older embedded validation section in examples (EN).
packages/components-dev/tag/template.html Removes legacy manual dev demo markup in favor of docs examples.
packages/components-dev/tag/styles.scss Removes unused dev-demo styles after template cleanup.
packages/components-dev/tag/module.ts Simplifies dev app to render docs examples (and adds new example).
Review details

Suppressed comments (1)

packages/components/tags/tag-input.ts:136

  • ngControl is injected with { optional: true } but the non-null assertion (!) makes the type/runtime contract incorrect (it will be null when no control is bound). Since this is a public property (even if deprecated), consider making it truly optional/nullable (e.g. ngControl?: NgControl or NgControl | null) and updating the API snapshot accordingly to avoid consumers hitting null-derefs.
    /**
     * The form control instance bound to the input, if any.
     *
     * @deprecated Unused. Bind `[formControl]`/`[ngModel]` to `<kbq-tag-list>` instead — it is the
     * single form control for the whole tag list. Will be removed in a future major release.
     * @docs-private
     */
    ngControl = inject(NgControl, { optional: true, self: true })!;
    /**
  • Files reviewed: 18/18 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread packages/components/tags/tag-input.ts Outdated

@lskramarov lskramarov left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review — fix(tags): stop bypassing validation on paste (#DS-2943)

The core direction is right: the input-level NgControl gate and the registerInput()setErrors bridge were genuinely broken (that bridge also wiped the tag list's own errors whenever the input control happened to be valid), and consolidating typed/blur/paste into one addTag() is a real improvement. The onPaste empty-data guard fix is correct — (data && data.length === 0) was dead code. I also ran the full gate set on this branch: jest (tags/form-field/autocomplete, 485 passed), eslint, stylelint, prettier, cspell, ngc --noEmit on docs-examples, and the example-module generator all pass, and the regenerated example-module.ts is byte-identical to what the generator produces.

15 findings below, most severe first.

Blocking-ish (consumer-visible):

  1. validation-tag-list — a shipped docs example relies on both removed mechanisms and is now a no-op demo whose control is permanently invalid.
  2. The ngControl deprecation and the new prose tell people to move [formControl]/[ngModel] off the input unconditionally — but that binding is the autocomplete's NG_VALUE_ACCESSOR in six examples.
  3. The pendingUIChange latch still leaks for rejected non-empty values — the exact pattern the new docs recommend — spuriously marking the control dirty on a later programmatic setValue.
  4. @else if in both validator examples hides co-occurring errors, reachable with the example's own options.

Correctness (pre-existing, but in code this PR rewrites): [distinct] still can't dedupe within a paste; blur() has no disabled guard.

Process: no BREAKING CHANGE: footer, no docs/guides/migration.{en,ru}.md entry, no schematic — fix(popover) (5e7db141a, same series) shipped all three for a smaller change. And the commit subject describes the opposite of what changed, which is what lands in the changelog.

Tests: 8 of the 12 new tests pass unchanged on main.

Docs: the stated default ErrorStateMatcher behaviour omits form.submitted; "regardless of its source" is not true for in-place tag editing (preventEditSubmit is the real hook and goes unmentioned).

Plus efficiency, reuse and duplicate-coverage notes inline.

🤖 Generated with Claude Code

Comment thread packages/components/tags/tag-list.component.ts
Comment thread packages/components/tags/tag-input.ts Outdated
Comment thread packages/components/tags/tag-input.ts
Comment thread packages/components/tags/tag-input.ts Outdated
Comment thread packages/components/tags/tag-input.en.md Outdated
Comment thread packages/components/tags/tag-input.spec.ts Outdated
Comment thread packages/components/tags/tag-input.ts Outdated
Comment thread packages/components/tags/tag-input.spec.ts Outdated
- migrate `validation-tag-list` example and the validation dev app off the
  input-level control onto tag-list validators
- clear the `pendingUIChange` latch when the consumer rejected a tag, so a later
  programmatic `setValue` no longer marks the control dirty
- skip tag creation on a blur caused by disabling the input
- dedupe pasted values against a value set built once per paste, which also
  closes the within-paste duplicate gap
- qualify the `ngControl` deprecation: binding a control to the input stays
  supported (autocomplete needs it), only its validators are ignored
- split co-occurring errors into one `<kbq-error>` per condition and replace the
  hand-rolled max-count validator with `Validators.maxLength`
- document the full default `ErrorStateMatcher` behaviour and `preventEditSubmit`
  for in-place editing
- reshape the validation tests so they fail against the pre-fix code and drop
  coverage duplicated in `tag-list.component.spec.ts`
- type `trimValue` and make `ngControl` nullable

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@artembelik artembelik changed the title fix(tags): stop bypassing validation on paste (#DS-2943) fix(tags): move validation to kbq-tag-list (#DS-2943) Sep 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants