2 changed files with 85 additions and 2 deletions
@ -0,0 +1,80 @@ |
|||||
|
///
|
||||
|
/// Copyright © 2016-2026 The Thingsboard Authors
|
||||
|
///
|
||||
|
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
/// you may not use this file except in compliance with the License.
|
||||
|
/// You may obtain a copy of the License at
|
||||
|
///
|
||||
|
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
///
|
||||
|
/// Unless required by applicable law or agreed to in writing, software
|
||||
|
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
/// See the License for the specific language governing permissions and
|
||||
|
/// limitations under the License.
|
||||
|
///
|
||||
|
|
||||
|
import { |
||||
|
Directive, |
||||
|
ElementRef, |
||||
|
OnDestroy, |
||||
|
inject, AfterViewInit, Renderer2, |
||||
|
} from '@angular/core'; |
||||
|
import { MatAutocompleteTrigger } from '@angular/material/autocomplete'; |
||||
|
import { Subscription } from 'rxjs'; |
||||
|
import { onParentScrollOrWindowResize } from '@core/utils'; |
||||
|
|
||||
|
@Directive({ |
||||
|
selector: 'input[matAutocomplete], textarea[matAutocomplete]', |
||||
|
standalone: false |
||||
|
}) |
||||
|
export class AutocompleteAutoScrollRepositionDirective implements AfterViewInit, OnDestroy { |
||||
|
private readonly trigger = inject(MatAutocompleteTrigger, { host: true }); |
||||
|
private readonly elementRef = inject(ElementRef<HTMLElement>); |
||||
|
private readonly renderer = inject(Renderer2); |
||||
|
|
||||
|
private parentScrollSubscription: Subscription = null; |
||||
|
private isIntersecting: boolean = false; |
||||
|
|
||||
|
private intersectionObserver = new IntersectionObserver((entries) => { |
||||
|
if (this.isIntersecting !== entries[0].isIntersecting) { |
||||
|
this.isIntersecting = entries[0].isIntersecting; |
||||
|
this.updatePanelVisibility(); |
||||
|
} |
||||
|
}, {threshold: [0.5]}); |
||||
|
|
||||
|
constructor() { |
||||
|
} |
||||
|
|
||||
|
ngAfterViewInit(): void { |
||||
|
this.parentScrollSubscription = onParentScrollOrWindowResize(this.elementRef.nativeElement).subscribe(() => { |
||||
|
if (this.trigger.panelOpen) { |
||||
|
this.trigger.updatePosition(); |
||||
|
} |
||||
|
}); |
||||
|
this.intersectionObserver.observe(this.elementRef.nativeElement); |
||||
|
} |
||||
|
|
||||
|
ngOnDestroy(): void { |
||||
|
if (this.parentScrollSubscription) { |
||||
|
this.parentScrollSubscription.unsubscribe(); |
||||
|
this.parentScrollSubscription = null; |
||||
|
} |
||||
|
if (this.intersectionObserver) { |
||||
|
this.intersectionObserver.unobserve(this.elementRef.nativeElement); |
||||
|
this.intersectionObserver.disconnect(); |
||||
|
this.intersectionObserver = null; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private updatePanelVisibility(): void { |
||||
|
if (this.trigger.panelOpen) { |
||||
|
if (this.isIntersecting) { |
||||
|
this.renderer.removeStyle(this.trigger.autocomplete.panel.nativeElement, 'display'); |
||||
|
} else { |
||||
|
this.renderer.setStyle(this.trigger.autocomplete.panel.nativeElement, 'display', 'none'); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
Loading…
Reference in new issue