fixed multiple autocomplete panel behavior

This commit is contained in:
Sofia Papacharalampous 2024-04-29 18:31:50 +03:00
parent 30d338bbbd
commit 7022de0bc8
3 changed files with 64 additions and 70 deletions

View File

@ -21,62 +21,64 @@
<div class="col-12"> <div class="col-12">
<input matInput #autocompleteInput [name]="id" autocomplete="nope" #autocompleteTrigger="matAutocompleteTrigger" autocomplete="off" [placeholder]="placeholder" [matAutocomplete]="autocomplete" [value]="inputValue" (keyup)="onKeyUp($event)" [disabled]="disabled" (focus)="_onInputFocus()" (blur)="onBlur($event)" [matChipInputFor]="chipList" [matChipInputSeparatorKeyCodes]="separatorKeysCodes" [matChipInputAddOnBlur]="autoSelectFirstOptionOnBlur" (matChipInputTokenEnd)="_addItem($event)"> <input matInput #autocompleteInput [name]="id" autocomplete="nope" #autocompleteTrigger="matAutocompleteTrigger" autocomplete="off" [placeholder]="placeholder" [matAutocomplete]="autocomplete" [value]="inputValue" (keyup)="onKeyUp($event)" [disabled]="disabled" (focus)="_onInputFocus()" (blur)="onBlur($event)" [matChipInputFor]="chipList" [matChipInputSeparatorKeyCodes]="separatorKeysCodes" [matChipInputAddOnBlur]="autoSelectFirstOptionOnBlur" (matChipInputTokenEnd)="_addItem($event)">
</div> </div>
<mat-autocomplete #autocomplete="matAutocomplete" [displayWith]="_displayFn.bind(this)" (optionSelected)="_optionSelected($event)"> <mat-autocomplete #autocomplete="matAutocomplete" [displayWith]="_displayFn.bind(this)" (optionSelected)="_optionSelected($event)" [classList]="['myClass']">
<span *ngIf="_groupedItems"> <div (mouseover)="isMouseOverPanel=true" (mouseout)="isMouseOverPanel=false">
<mat-optgroup *ngFor="let group of _groupedItems | async" [label]="group.title"> <span *ngIf="_groupedItems">
<mat-option *ngFor="let item of group.items" [value]="item" class="option" [class.two-line-mat-option]="_subtitleFn(item) && !_optionTemplate(item) && !_optionComponent(item)"> <mat-optgroup *ngFor="let group of _groupedItems | async" [label]="group.title">
<!-- <img style="vertical-align:middle;" aria-hidden src="{{state.flag}}" height="25" /> --> <mat-option *ngFor="let item of group.items" [value]="item" class="option" [class.two-line-mat-option]="_subtitleFn(item) && !_optionTemplate(item) && !_optionComponent(item)" (optionActivated)="clickedOnPanel()">
<ng-container *ngIf="_optionComponent(item)">
<ng-container *ngComponentOutlet="_optionComponent(item); inputs: { item };" />
</ng-container>
<ng-template #cellTemplate *ngIf="_optionTemplate(item) && !_optionComponent(item)" [ngTemplateOutlet]="_optionTemplate(item)" [ngTemplateOutletContext]="{
item: item
}"></ng-template>
<div *ngIf="!_optionTemplate(item)" class="d-flex">
<div class="title-subtitle-fn">
<div class="title-fn">
<div class="title-fn-inner">
<span *ngIf="!_optionTemplate(item)" class="title-text">{{_titleFn(item)}}</span>
</div>
</div>
<div *ngIf="_subtitleFn(item)" class="subtitle-fn">
<div class="subtitle-fn-inner">
<small [innerHTML]="_subtitleFn(item)" class="subtitle-text"></small>
</div>
</div>
</div>
<span *ngIf="popupItemActionIcon" class="option-icon" (click)="_optionActionClick(item, $event)"><mat-icon>{{popupItemActionIcon}}</mat-icon></span>
</div>
</mat-option>
</mat-optgroup>
</span>
<span *ngIf="!_groupedItems">
<div *ngIf="_items | async as autocompleteItems; else loading">
<ng-container *ngIf="autocompleteItems.length; else noItems">
<mat-option *ngFor="let item of autocompleteItems" class="option" [value]="item" [class.two-line-mat-option]="_subtitleFn(item) && !_optionTemplate(item) && !_optionComponent(item)">
<!-- <img style="vertical-align:middle;" aria-hidden src="{{state.flag}}" height="25" /> --> <!-- <img style="vertical-align:middle;" aria-hidden src="{{state.flag}}" height="25" /> -->
<ng-container *ngIf="_optionComponent(item)"> <ng-container *ngIf="_optionComponent(item)">
<ng-container *ngComponentOutlet="_optionComponent(item); inputs: { item };" /> <ng-container *ngComponentOutlet="_optionComponent(item); inputs: { item };" />
</ng-container> </ng-container>
<ng-template #cellTemplate *ngIf="_optionTemplate(item) && !_optionComponent(item)" [ngTemplateOutlet]="_optionTemplate(item)" [ngTemplateOutletContext]="{ <ng-template #cellTemplate *ngIf="_optionTemplate(item) && !_optionComponent(item)" [ngTemplateOutlet]="_optionTemplate(item)" [ngTemplateOutletContext]="{
item: item item: item
}"></ng-template> }"></ng-template>
<div *ngIf="!_optionTemplate(item) && !_optionComponent(item)"> <div *ngIf="!_optionTemplate(item)" class="d-flex">
<span class="title-text">{{_titleFn(item)}}</span> <div class="title-subtitle-fn">
<br *ngIf="_subtitleFn(item)"> <div class="title-fn">
<small *ngIf="_subtitleFn(item)" class="subtitle-text">{{_subtitleFn(item)}}</small> <div class="title-fn-inner">
<span *ngIf="!_optionTemplate(item)" class="title-text">{{_titleFn(item)}}</span>
</div>
</div>
<div *ngIf="_subtitleFn(item)" class="subtitle-fn">
<div class="subtitle-fn-inner">
<small [innerHTML]="_subtitleFn(item)" class="subtitle-text"></small>
</div>
</div>
</div>
<span *ngIf="popupItemActionIcon" class="option-icon" (click)="_optionActionClick(item, $event)"><mat-icon>{{popupItemActionIcon}}</mat-icon></span> <span *ngIf="popupItemActionIcon" class="option-icon" (click)="_optionActionClick(item, $event)"><mat-icon>{{popupItemActionIcon}}</mat-icon></span>
</div> </div>
</mat-option> </mat-option>
</ng-container> </mat-optgroup>
<ng-template #noItems> </span>
<mat-option disabled="true">No results found!</mat-option> <span *ngIf="!_groupedItems">
<div *ngIf="_items | async as autocompleteItems; else loading">
<ng-container *ngIf="autocompleteItems.length; else noItems">
<mat-option *ngFor="let item of autocompleteItems" class="option" [value]="item" [class.two-line-mat-option]="_subtitleFn(item) && !_optionTemplate(item) && !_optionComponent(item)" (optionActivated)="clickedOnPanel()">
<!-- <img style="vertical-align:middle;" aria-hidden src="{{state.flag}}" height="25" /> -->
<ng-container *ngIf="_optionComponent(item)">
<ng-container *ngComponentOutlet="_optionComponent(item); inputs: { item };" />
</ng-container>
<ng-template #cellTemplate *ngIf="_optionTemplate(item) && !_optionComponent(item)" [ngTemplateOutlet]="_optionTemplate(item)" [ngTemplateOutletContext]="{
item: item
}"></ng-template>
<div *ngIf="!_optionTemplate(item) && !_optionComponent(item)">
<span class="title-text">{{_titleFn(item)}}</span>
<br *ngIf="_subtitleFn(item)">
<small *ngIf="_subtitleFn(item)" class="subtitle-text">{{_subtitleFn(item)}}</small>
<span *ngIf="popupItemActionIcon" class="option-icon" (click)="_optionActionClick(item, $event)"><mat-icon>{{popupItemActionIcon}}</mat-icon></span>
</div>
</mat-option>
</ng-container>
<ng-template #noItems>
<mat-option disabled="true">No results found!</mat-option>
</ng-template>
</div>
<ng-template #loading>
<mat-option disabled="true">loading...</mat-option>
</ng-template> </ng-template>
</div> </span>
<ng-template #loading> </div>
<mat-option disabled="true">loading...</mat-option>
</ng-template>
</span>
</mat-autocomplete> </mat-autocomplete>
</div> </div>
</div> </div>

View File

@ -1,22 +1,6 @@
import { FocusMonitor } from '@angular/cdk/a11y'; import { FocusMonitor } from '@angular/cdk/a11y';
import { ENTER } from '@angular/cdk/keycodes'; import { ENTER } from '@angular/cdk/keycodes';
import { import { Component, DoCheck, ElementRef, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Optional, Output, Self, SimpleChanges, TemplateRef, Type, ViewChild } from '@angular/core';
Component,
DoCheck,
ElementRef,
EventEmitter,
Input,
OnChanges,
OnDestroy,
OnInit,
Optional,
Output,
Self,
SimpleChanges,
TemplateRef,
Type,
ViewChild
} from '@angular/core';
import { ControlValueAccessor, FormGroupDirective, NgControl, NgForm } from '@angular/forms'; import { ControlValueAccessor, FormGroupDirective, NgControl, NgForm } from '@angular/forms';
import { MatAutocomplete, MatAutocompleteSelectedEvent, MatAutocompleteTrigger } from '@angular/material/autocomplete'; import { MatAutocomplete, MatAutocompleteSelectedEvent, MatAutocompleteTrigger } from '@angular/material/autocomplete';
import { MatChipInputEvent } from '@angular/material/chips'; import { MatChipInputEvent } from '@angular/material/chips';
@ -27,7 +11,7 @@ import {
MultipleAutoCompleteConfiguration MultipleAutoCompleteConfiguration
} from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration'; } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration';
import { BaseComponent } from '@common/base/base.component'; import { BaseComponent } from '@common/base/base.component';
import { BehaviorSubject, Observable, Subject, interval, of as observableOf, of } from 'rxjs'; import { BehaviorSubject, Observable, Subject, Subscription, interval, of as observableOf, of } from 'rxjs';
import { catchError, debounceTime, delayWhen, distinctUntilChanged, map, mergeMap, startWith, switchMap, take, takeUntil } from 'rxjs/operators'; import { catchError, debounceTime, delayWhen, distinctUntilChanged, map, mergeMap, startWith, switchMap, take, takeUntil } from 'rxjs/operators';
export class CustomComponentBase extends BaseComponent { export class CustomComponentBase extends BaseComponent {
@ -98,6 +82,9 @@ export class MultipleAutoCompleteComponent extends _CustomComponentMixinBase imp
selectable = false; selectable = false;
selected: boolean = false; selected: boolean = false;
isMouseOverPanel: boolean = false;
panelClosedSubscription: Subscription;
get empty() { get empty() {
return (!this.value || this.value.length === 0) && (!this.inputValue || this.inputValue.length === 0); return (!this.value || this.value.length === 0) && (!this.inputValue || this.inputValue.length === 0);
} }
@ -182,9 +169,9 @@ export class MultipleAutoCompleteComponent extends _CustomComponentMixinBase imp
this.focused = !!origin; this.focused = !!origin;
this.stateChanges.next(); this.stateChanges.next();
// if (!this.focused) { if (!this.isMouseOverPanel && !this.focused) {
// this.autocompleteTrigger?.closePanel(); this.autocompleteTrigger?.closePanel();
// } }
}); });
if (this.ngControl != null) { if (this.ngControl != null) {
@ -194,7 +181,11 @@ export class MultipleAutoCompleteComponent extends _CustomComponentMixinBase imp
} }
} }
ngOnInit() { } ngOnInit() {
this.panelClosedSubscription = this.autocomplete.closed.subscribe((next) => {
this.isMouseOverPanel=false;
})
}
ngDoCheck(): void { ngDoCheck(): void {
if (this.ngControl) { if (this.ngControl) {
@ -358,6 +349,7 @@ export class MultipleAutoCompleteComponent extends _CustomComponentMixinBase imp
this.stateChanges.complete(); this.stateChanges.complete();
this.fm.stopMonitoring(this.elRef.nativeElement); this.fm.stopMonitoring(this.elRef.nativeElement);
this.gettingSelectedItem$.complete(); this.gettingSelectedItem$.complete();
this.panelClosedSubscription.unsubscribe();
} }
//Configuration getters //Configuration getters

View File

@ -395,7 +395,7 @@
.stepper-actions { .stepper-actions {
display: flex; display: flex;
padding-left: 1rem; // padding-left: 1rem;
margin-top: auto; margin-top: auto;
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
// margin-top: 5rem; // margin-top: 5rem;