ng-select icon indicating copy to clipboard operation
ng-select copied to clipboard

Fix addTag and virtual scroll dropdown panel height

Open troehling opened this issue 1 year ago • 2 comments

Fixes #1700: The height of the dropdown panel does not consider the add tag entries when virtual scroll is active.

Explanation and and reproducible example is included in the referenced issue. The issue is still reproducible with the current version.

The issue is that the addTag is not included in the regular list of items but rendered separately. As the height calculation is based solely on the number of regular items, the addTag is not considered. To compensate for that I passed the information whether the button is displayed or not as an additional parameter to the NgDropdownPanelComponent and increment the itemsLength in case the addTag is displayed.

troehling avatar Dec 03 '24 12:12 troehling

This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions :fireworks:

github-actions[bot] avatar Feb 02 '25 01:02 github-actions[bot]

This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions :fireworks:

github-actions[bot] avatar May 12 '25 01:05 github-actions[bot]

This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions :fireworks:

github-actions[bot] avatar Jul 19 '25 01:07 github-actions[bot]

@troehling please fix conflicts

pavankjadda avatar Jul 30 '25 17:07 pavankjadda

@pavankjadda I rebased but I did not get any conflicts. Is it sufficient this way or am I missing something?

troehling avatar Aug 01 '25 11:08 troehling

This small fix closes a 5-year-old (!) issue, would be great to merge.

shamoon avatar Sep 07 '25 16:09 shamoon

@troehling I think this does need a rebase as there are conflicts (even though GH is not showing them above)

diff --cc src/ng-select/lib/ng-dropdown-panel.component.ts
index ba54c1b,dbcae2e..0000000
--- a/src/ng-select/lib/ng-dropdown-panel.component.ts
+++ b/src/ng-select/lib/ng-dropdown-panel.component.ts
@@@ -51,44 -54,36 +51,58 @@@ const SCROLL_SCHEDULER = typeof request
                        </div>
                }
        `,
 -      imports: [NgTemplateOutlet],
 +      imports: [NgTemplateOutlet]
  })
  export class NgDropdownPanelComponent implements OnInit, OnChanges, OnDestroy {
++<<<<<<< HEAD
 +      private _renderer = inject(Renderer2);
 +      private _zone = inject(NgZone);
 +      private _panelService = inject(NgDropdownPanelService);
 +      private _document = inject(DOCUMENT, { optional: true })!;
 +      private _dropdown = inject(ElementRef<HTMLElement>).nativeElement;
++=======
+       @Input() items: NgOption[] = [];
+       @Input() showAddTag: boolean = false;
+       @Input() markedItem: NgOption;
+       @Input() position: DropdownPosition = 'auto';
+       @Input() appendTo: string;
+       @Input() bufferAmount: number;
+       @Input({ transform: booleanAttribute }) virtualScroll = false;
+       @Input() headerTemplate: TemplateRef<any>;
+       @Input() footerTemplate: TemplateRef<any>;
+       @Input() filterValue: string = null;
+       ariaLabelDropdown = input<string | null>(null);
 -
 -      @Output() update = new EventEmitter<any[]>();
 -      @Output() scroll = new EventEmitter<{ start: number; end: number }>();
 -      @Output() scrollToEnd = new EventEmitter<void>();
 -      @Output() outsideClick = new EventEmitter<void>();
 -
 -      @ViewChild('content', { read: ElementRef, static: true }) contentElementRef: ElementRef;
 -      @ViewChild('scroll', { read: ElementRef, static: true }) scrollElementRef: ElementRef;
 -      @ViewChild('padding', { read: ElementRef, static: true }) paddingElementRef: ElementRef;
++>>>>>>> bbbc168 (Fix addTag and virtual scroll dropdown panel height)
 +
 +      readonly items = input<NgOption[]>([]);
 +      readonly markedItem = input<NgOption>(undefined);
 +      readonly position = input<DropdownPosition>('auto');
 +      readonly appendTo = input<string>(undefined);
 +      readonly bufferAmount = input<number>(undefined);
 +      readonly virtualScroll = input(false, { transform: booleanAttribute });
 +      readonly headerTemplate = input<TemplateRef<any>>(undefined);
 +      readonly footerTemplate = input<TemplateRef<any>>(undefined);
 +      readonly filterValue = input<string>(null);
 +      readonly ariaLabelDropdown = input<string | null>(null);
 +
 +      readonly update = output<any[]>();
 +      readonly scroll = output<{
 +              start: number;
 +              end: number;
 +      }>();
 +      readonly scrollToEnd = output<void>();
 +      readonly outsideClick = output<void>();
 +
 +      private readonly contentElementRef = viewChild('content', { read: ElementRef });
 +      private readonly scrollElementRef = viewChild('scroll', { read: ElementRef });
 +      private readonly paddingElementRef = viewChild('padding', { read: ElementRef });

        private readonly _destroy$ = new Subject<void>();
 -      private readonly _dropdown: HTMLElement;
 -      private _virtualPadding: HTMLElement;
 -      private _scrollablePanel: HTMLElement;
 -      private _contentPanel: HTMLElement;
 -      private _select: HTMLElement;
 +      private readonly _virtualPadding = computed(() => this.paddingElementRef()?.nativeElement);
 +      private readonly _scrollablePanel = computed(() => this.scrollElementRef()?.nativeElement);
 +      private readonly _contentPanel = computed(() => this.contentElementRef()?.nativeElement);
 +
 +      private _select: HTMLElement | undefined;
        private _parent: HTMLElement;
        private _scrollToEndFired = false;
        private _updateScrollHeight = false;
@@@ -250,11 -259,14 +268,22 @@@
                this._zone.run(() => this.outsideClick.emit());
        }

++<<<<<<< HEAD
 +      private _onItemsChange(items: NgOption[] = [], firstChange: boolean) {
 +              this._scrollToEndFired = false;
 +              this.itemsLength = items.length;
 +
 +              if (this.virtualScroll()) {
++=======
+       private _onItemsOrShowAddTagChange(items: NgOption[], showAddTag: boolean, firstChange: boolean) {
+               this.items = items || [];
+               this._scrollToEndFired = false;
+               this.itemsLength = items.length;
+               if (showAddTag && !(items.length === 0)) {
+                       this.itemsLength++;
+               }
+               if (this.virtualScroll) {
++>>>>>>> bbbc168 (Fix addTag and virtual scroll dropdown panel height)
                        this._updateItemsRange(firstChange);
                } else {
                        this._setVirtualHeight();

Let me know if I can help in any way (e.g. if you give me write access to your fork I can help get this over the line, but no pressure of course)

shamoon avatar Sep 08 '25 15:09 shamoon

@shamoon I rebased it now. Hopefully that worked out. I also granted you write access in case there is something pending to do.

troehling avatar Sep 09 '25 05:09 troehling

Thanks! Will certainly help if I can.

shamoon avatar Sep 09 '25 06:09 shamoon

@pavankjadda or @saibaburaavi would really appreciate a look here, again the bug is years old

shamoon avatar Sep 12 '25 14:09 shamoon

Hopefully should be good here if you dont mind re-triggering the workflow @pavankjadda 🙏

Initial chunk files                        | Names                                   |  Raw size
chunk-PX7XMSCE.js                          | -                                       |   2.39 MB | 
chunk-RD665U2J.js                          | -                                       |   1.10 MB | 
polyfills.js                               | polyfills                               |   1.01 MB | 
spec-lib-ng-select.component.spec.js       | spec-lib-ng-select.component.spec       | 223.33 kB | 
chunk-B5AKN72Z.js                          | -                                       |  67.20 kB | 
chunk-J6FNGYNQ.js                          | -                                       |  38.75 kB | 
spec-lib-items-list.spec.js                | spec-lib-items-list.spec                |  22.97 kB | 
test_main.js                               | test_main                               |  21.67 kB | 
spec-lib-ng-dropdown-panel.service.spec.js | spec-lib-ng-dropdown-panel.service.spec |   2.64 kB | 
chunk-TTULUY32.js                          | -                                       |   1.99 kB | 
jasmine-cleanup-0.js                       | jasmine-cleanup-0                       | 519 bytes | 
jasmine-cleanup-1.js                       | jasmine-cleanup-1                       | 106 bytes | 

                                           | Initial total                           |   4.88 MB

Application bundle generation complete. [2.308 seconds]

23 09 2025 13:55:37.196:INFO [karma-server]: Karma v6.4.4 server started at http://localhost:9876/
23 09 2025 13:55:37.197:INFO [launcher]: Launching browsers ChromeHeadless with concurrency unlimited
23 09 2025 13:55:37.199:INFO [launcher]: Starting browser ChromeHeadless
23 09 2025 13:55:37.777:INFO [Chrome Headless 140.0.0.0 (Mac OS 10.15.7)]: Connected on socket vY2DeriSH_0prqSNAAAB with id 33834035
Chrome Headless 140.0.0.0 (Mac OS 10.15.7): Executed 315 of 315 SUCCESS (0.926 secs / 0.847 secs)
TOTAL: 315 SUCCESS
TOTAL: 315 SUCCESS

=============================== Coverage summary ===============================
Statements   : 94.08% ( 1033/1098 )
Branches     : 86.41% ( 477/552 )
Functions    : 96.44% ( 244/253 )
Lines        : 93.98% ( 985/1048 )
================================================================================
Initial chunk files                            | Names                                       |  Raw size
chunk-67HTMDRQ.js                              | -                                           |   2.23 MB | 
polyfills.js                                   | polyfills                                   |   1.01 MB | 
jasmine-cleanup-1.js                           | jasmine-cleanup-1                           |  67.20 kB | 
spec-lib-ng-option-highlight.directive.spec.js | spec-lib-ng-option-highlight.directive.spec |  44.95 kB | 
test_main.js                                   | test_main                                   |  21.25 kB | 
chunk-EVSPGG2W.js                              | -                                           |   1.64 kB | 
jasmine-cleanup-0.js                           | jasmine-cleanup-0                           | 519 bytes | 

                                               | Initial total                               |   3.37 MB

Application bundle generation complete. [1.420 seconds]

23 09 2025 13:55:40.648:INFO [karma-server]: Karma v6.4.4 server started at http://localhost:9876/
23 09 2025 13:55:40.648:INFO [launcher]: Launching browsers ChromeHeadless with concurrency unlimited
23 09 2025 13:55:40.650:INFO [launcher]: Starting browser ChromeHeadless
23 09 2025 13:55:41.209:INFO [Chrome Headless 140.0.0.0 (Mac OS 10.15.7)]: Connected on socket w01_OevJup_Fuit5AAAD with id 86746019
Chrome Headless 140.0.0.0 (Mac OS 10.15.7): Executed 9 of 9 SUCCESS (0.033 secs / 0.03 secs)
TOTAL: 9 SUCCESS
TOTAL: 9 SUCCESS

=============================== Coverage summary ===============================
Statements   : 100% ( 24/24 )
Branches     : 100% ( 7/7 )
Functions    : 100% ( 8/8 )
Lines        : 100% ( 24/24 )
================================================================================
✨  Done in 7.77s.

shamoon avatar Sep 23 '25 20:09 shamoon

@pavankjadda I think the copilot suggestion was in fact wrong

Verifying the current code works as expected:

Screenshot 2025-09-24 at 11 12 16 AM Screenshot 2025-09-24 at 11 12 20 AM

with 0 items: Screenshot 2025-09-24 at 11 14 29 AM Screenshot 2025-09-24 at 11 14 34 AM

vs Copilot suggestion: Screenshot 2025-09-24 at 11 15 55 AM

vs before:

Screenshot 2025-09-24 at 11 12 04 AM

Also the last CI failure doesnt seem related to this PR:

📄 Using coverage file: ./coverage/ng-select/lcov.info
🚀 Posting coverage data to https://coveralls.io/api/v1/jobs
⚠️ Internal server error. Please contact Coveralls team.
Error: Process completed with exit code 1.

shamoon avatar Sep 24 '25 18:09 shamoon

Awesome work @troehling , let's get this in please!

applebum-oot avatar Oct 02 '25 05:10 applebum-oot

@saibaburaavi any plans an merging this?

david-loe avatar Oct 21 '25 17:10 david-loe

Because it's been left open conflicts keep cropping up from other changes in the main branch, unfortunately. I will fix it now but yes it would be great to finally get this merged, or at least some discussion of why not

shamoon avatar Oct 21 '25 17:10 shamoon

Again, merge conflicts resolved. If there is something preventing merge please tell us, rather than silently waiting until conflicts crop up again...

shamoon avatar Nov 02 '25 19:11 shamoon

@shamoon @troehling Sorry for delay. I will review and merge this asap

pavankjadda avatar Nov 03 '25 14:11 pavankjadda

Coverage Status

coverage: 91.945% (+0.05%) from 91.894% when pulling c3d0ab28ff72932246143f90d82f2afa2b790356 on troehling:master into 6e0b09b973bcd08c78d1934de9135e3b7cac07c9 on ng-select:master.

coveralls avatar Nov 03 '25 14:11 coveralls

:tada: This PR is included in version 20.6.2 :tada:

The release is available on:

Your semantic-release bot :package::rocket:

github-actions[bot] avatar Nov 03 '25 16:11 github-actions[bot]