Skip to content

Conversation

@PatrickKaster
Copy link

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Other... Please describe:

What is the current behavior?

When using @siemens/ngx-datatable with Angular 20, sorting fails after data updates.
During Angular’s reactive signal recomputation, the library’s internal sort cache (cachedDir) may contain an undefined comparator function, causing:

TypeError: cachedDir.compareFn is not a function

This occurs inside sortRows() when Angular 20 recomputes internal rows via computed(), which can cause comparator references to be lost.

Affected versions:

  • ngx-datatable: 24.x – 25.0.0
  • Angular: 20.x

Sorting and table updates break after CRUD operations.


What is the new behavior?

A safe fallback is added so the comparator function is always valid:

  1. Fallback to orderByComparator if a column’s comparator is undefined:
const compareFn = cols[dir.prop] ?? orderByComparator;
  1. Runtime safety added to ensure the comparator is always callable:
(cachedDir.compareFn ?? orderByComparator)(...)

This prevents comparator loss during Angular 20’s signal recomputation and ensures that sorting works correctly after data updates.

Additional improvements:

  • Sorting remains reliable even when comparator functions are not explicitly defined.
  • Compatible with Angular 20’s reactive primitives.
  • Backward compatible with Angular 19 and earlier.

Tests added include:

  • Sorting with undefined comparator
  • Sorting during reactive updates
  • Regression tests for existing functionality

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

  • Fixes: cachedDir.compareFn is not a function during sorting in Angular 20
  • No application code changes are required for library users

- Add fallback to orderByComparator when column comparator is undefined
- Prevent TypeError during sorting operations in Angular 20 reactive context
- Add comprehensive tests for sorting with undefined comparators
- Include test simulating Angular 20 reactive context with computed signals

Fixes issue where cachedDir.compareFn is not a function during data updates
@PatrickKaster PatrickKaster requested a review from a team as a code owner December 12, 2025 17:54
@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.


Patrick Kaster seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

@gemini-code-assist
Copy link

Summary of Changes

Hello @PatrickKaster, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses a critical bug in the @siemens/ngx-datatable library that caused sorting failures in Angular 20 applications. The issue stemmed from comparator functions becoming undefined during Angular's reactive signal recomputation, leading to runtime errors. The solution introduces resilient fallback logic to ensure that sorting operations always have a valid comparator, thereby restoring reliable data sorting behavior across reactive updates and maintaining full compatibility with previous Angular versions.

Highlights

  • Bug Fix for Angular 20 Sorting: Resolves a "TypeError: cachedDir.compareFn is not a function" error that occurred in @siemens/ngx-datatable when sorting with Angular 20, due to comparator functions becoming undefined during reactive signal recomputation.
  • Robust Comparator Fallback: Implements two fallback mechanisms using the nullish coalescing operator (??) to ensure that a valid comparator function (orderByComparator) is always used, even if a column's specific comparator becomes undefined.
  • Enhanced Test Coverage: Adds new unit tests specifically for scenarios involving undefined comparators and reactive sorting with Angular signals, validating the robustness of the fix.
  • Backward Compatibility: The changes are fully backward compatible with Angular 19 and earlier versions, requiring no application code changes for library users.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request effectively resolves a sorting issue encountered with Angular 20 by providing a fallback comparator. The changes are logical, and the addition of a new test file with specific scenarios, including reactive updates, is a great way to ensure the fix is robust and prevents future regressions. I have one suggestion regarding code clarity in sort.ts where a fallback appears to be redundant. Overall, this is a well-executed fix.

Comment on lines +134 to +135
? (cachedDir.compareFn ?? orderByComparator)(propA, propB, rowA, rowB)
: -(cachedDir.compareFn ?? orderByComparator)(propA, propB, rowA, rowB);

Choose a reason for hiding this comment

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

medium

The fallback to orderByComparator here appears to be redundant. The cachedDir.compareFn is assigned its value on line 113, which is derived from the compareFn constant defined on line 108:

const compareFn = cols[dir.prop] ?? orderByComparator;

This initial assignment already ensures that cachedDir.compareFn will hold a valid function, defaulting to orderByComparator if the column-specific comparator is missing. Consequently, the nullish coalescing operators (??) in this block are not necessary. Removing them would improve code clarity by avoiding the implication that cachedDir.compareFn could be nullish at this stage.

Suggested change
? (cachedDir.compareFn ?? orderByComparator)(propA, propB, rowA, rowB)
: -(cachedDir.compareFn ?? orderByComparator)(propA, propB, rowA, rowB);
? cachedDir.compareFn(propA, propB, rowA, rowB)
: -cachedDir.compareFn(propA, propB, rowA, rowB);

@spike-rabbit
Copy link
Member

THX a lot for your contribution @PatrickKaster. I am not able to reproduce your issue. Can you please create a reproduction here https://stackblitz.com/fork/github/siemens/ngx-datatable/tree/main/projects/stackblitz and share the link.

In general, the comparator should never be undefined for a column which has sorting enabled. So I believe the actual error happens somewhere else.

@PatrickKaster
Copy link
Author

Hi @spike-rabbit,

Thank you for looking into this. I completely understand the hesitation since it isn't reproducible in an isolated StackBlitz.

To be transparent: I am also unsure if the root cause lies entirely within the library or if it's an edge-case interaction with how our application handles async state updates via STOMP in Angular 20. Our runtime logs confirm that cachedDir.compareFn occasionally loses its function reference during the ngDoCheck cycle, but we haven't been able to decouple this from our backend stack for a minimal repro.

How we mitigated this:
We have since moved to external sorting. By sorting the data in our application logic before it reaches the table, we bypassed the internal sortRows path, which has resolved the crashes for us.

Regarding this PR:
I don't want to unduly push for this merge without a clear reproduction. My intent was to offer a defensive safety measure—ensuring that if the state becomes inconsistent (for whatever reason), the library defaults to a standard sort rather than throwing a TypeError that crashes the UI.

If you prefer to keep the library strict, I am happy to close this. However, if you see value in this guard for the sake of overall stability, the PR is available for consideration.

Thanks again for your time and for maintaining this project!

@spike-rabbit
Copy link
Member

spike-rabbit commented Jan 14, 2026

@PatrickKaster I hope we will find the root cause for this behavior.

In your application, do you set the [sorts] input of the datatable? If yes, can you verify that all columns are sortable which you may pass to the sortable input?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants