UI: Error icon with tooltip for toggle select
This commit is contained in:
		
							parent
							
								
									052bfc09dd
								
							
						
					
					
						commit
						d3e20161c9
					
				@ -41,10 +41,10 @@
 | 
			
		||||
      </div>
 | 
			
		||||
      <tb-toggle-select [(ngModel)]="dataLayerMode"
 | 
			
		||||
                        [ngModelOptions]="{ standalone: true }">
 | 
			
		||||
        <tb-toggle-option *ngIf="trip" value="trips">{{ 'widgets.maps.overlays.trips' | translate }}</tb-toggle-option>
 | 
			
		||||
        <tb-toggle-option value="markers">{{ 'widgets.maps.overlays.markers' | translate }}</tb-toggle-option>
 | 
			
		||||
        <tb-toggle-option value="polygons">{{ 'widgets.maps.overlays.polygons' | translate }}</tb-toggle-option>
 | 
			
		||||
        <tb-toggle-option value="circles">{{ 'widgets.maps.overlays.circles' | translate }}</tb-toggle-option>
 | 
			
		||||
        <tb-toggle-option *ngIf="trip" value="trips" [error]="mapSettingsFormGroup.get('trips').invalid" errorText="widgets.maps.overlays.required-fields">{{ 'widgets.maps.overlays.trips' | translate }}</tb-toggle-option>
 | 
			
		||||
        <tb-toggle-option value="markers" [error]="mapSettingsFormGroup.get('markers').invalid" errorText="widgets.maps.overlays.required-fields">{{ 'widgets.maps.overlays.markers' | translate }}</tb-toggle-option>
 | 
			
		||||
        <tb-toggle-option value="polygons" [error]="mapSettingsFormGroup.get('polygons').invalid" errorText="widgets.maps.overlays.required-fields">{{ 'widgets.maps.overlays.polygons' | translate }}</tb-toggle-option>
 | 
			
		||||
        <tb-toggle-option value="circles" [error]="mapSettingsFormGroup.get('circles').invalid" errorText="widgets.maps.overlays.required-fields">{{ 'widgets.maps.overlays.circles' | translate }}</tb-toggle-option>
 | 
			
		||||
      </tb-toggle-select>
 | 
			
		||||
    </div>
 | 
			
		||||
    <tb-map-data-layers *ngIf="trip"
 | 
			
		||||
 | 
			
		||||
@ -41,7 +41,16 @@
 | 
			
		||||
                           [name]="name"
 | 
			
		||||
                           [(ngModel)]="value"
 | 
			
		||||
                           (ngModelChange)="valueChange.emit(value)">
 | 
			
		||||
    <mat-button-toggle *ngFor="let option of options; trackBy: trackByHeaderOption" [value]="option.value" [disabled]="disabled">{{ option.name }}</mat-button-toggle>
 | 
			
		||||
    <mat-button-toggle *ngFor="let option of options; trackBy: trackByHeaderOption" [value]="option.value" [disabled]="disabled">
 | 
			
		||||
      {{ option.name }}
 | 
			
		||||
      <mat-icon matTooltipPosition="above"
 | 
			
		||||
                matTooltipClass="tb-error-tooltip"
 | 
			
		||||
                [matTooltip]="option.errorText | translate"
 | 
			
		||||
                *ngIf="option.error && value !== option.value"
 | 
			
		||||
                class="tb-error tb-error-icon">
 | 
			
		||||
        warning
 | 
			
		||||
      </mat-icon>
 | 
			
		||||
    </mat-button-toggle>
 | 
			
		||||
  </mat-button-toggle-group>
 | 
			
		||||
</div>
 | 
			
		||||
<button mat-icon-button
 | 
			
		||||
 | 
			
		||||
@ -43,6 +43,12 @@
 | 
			
		||||
  .tb-toggle-header {
 | 
			
		||||
    transition: transform 500ms cubic-bezier(0.35, 0, 0.25, 1);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .tb-error-icon {
 | 
			
		||||
    width: 12px;
 | 
			
		||||
    height: 12px;
 | 
			
		||||
    font-size: 12px;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
:host ::ng-deep {
 | 
			
		||||
 | 
			
		||||
@ -16,7 +16,8 @@
 | 
			
		||||
 | 
			
		||||
import {
 | 
			
		||||
  AfterContentChecked,
 | 
			
		||||
  AfterContentInit, AfterViewChecked,
 | 
			
		||||
  AfterContentInit,
 | 
			
		||||
  AfterViewChecked,
 | 
			
		||||
  AfterViewInit,
 | 
			
		||||
  ChangeDetectorRef,
 | 
			
		||||
  Component,
 | 
			
		||||
@ -25,11 +26,14 @@ import {
 | 
			
		||||
  ElementRef,
 | 
			
		||||
  EventEmitter,
 | 
			
		||||
  HostBinding,
 | 
			
		||||
  Input, NgZone,
 | 
			
		||||
  Input,
 | 
			
		||||
  NgZone,
 | 
			
		||||
  OnChanges,
 | 
			
		||||
  OnDestroy,
 | 
			
		||||
  OnInit,
 | 
			
		||||
  Output,
 | 
			
		||||
  QueryList,
 | 
			
		||||
  SimpleChanges,
 | 
			
		||||
  ViewChild
 | 
			
		||||
} from '@angular/core';
 | 
			
		||||
import { PageComponent } from '@shared/components/page.component';
 | 
			
		||||
@ -42,10 +46,13 @@ import { coerceBoolean } from '@shared/decorators/coercion';
 | 
			
		||||
import { startWith, takeUntil } from 'rxjs/operators';
 | 
			
		||||
import { Platform } from '@angular/cdk/platform';
 | 
			
		||||
import { MatButtonToggle, MatButtonToggleGroup } from '@angular/material/button-toggle';
 | 
			
		||||
import { isDefinedAndNotNull } from '@core/utils';
 | 
			
		||||
 | 
			
		||||
export interface ToggleHeaderOption {
 | 
			
		||||
  name: string;
 | 
			
		||||
  value: any;
 | 
			
		||||
  error?: boolean;
 | 
			
		||||
  errorText?: any;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type ToggleHeaderAppearance = 'fill' | 'fill-invert' | 'stroked';
 | 
			
		||||
@ -59,10 +66,16 @@ export type ScrollDirection = 'after' | 'before';
 | 
			
		||||
  }
 | 
			
		||||
)
 | 
			
		||||
// eslint-disable-next-line @angular-eslint/directive-class-suffix
 | 
			
		||||
export class ToggleOption {
 | 
			
		||||
export class ToggleOption implements OnChanges {
 | 
			
		||||
 | 
			
		||||
  @Input() value: any;
 | 
			
		||||
 | 
			
		||||
  @Input() error: boolean;
 | 
			
		||||
 | 
			
		||||
  @Input() errorText: any;
 | 
			
		||||
 | 
			
		||||
  @Output() errorChange = new EventEmitter<boolean>();
 | 
			
		||||
 | 
			
		||||
  get viewValue(): string {
 | 
			
		||||
    return (this._element?.nativeElement.textContent || '').trim();
 | 
			
		||||
  }
 | 
			
		||||
@ -70,6 +83,14 @@ export class ToggleOption {
 | 
			
		||||
  constructor(
 | 
			
		||||
    private _element: ElementRef<HTMLElement>
 | 
			
		||||
  ) {}
 | 
			
		||||
 | 
			
		||||
  ngOnChanges(changes: SimpleChanges) {
 | 
			
		||||
    if (changes['error']) {
 | 
			
		||||
      if (!changes['error'].firstChange && changes['error'].currentValue !== changes['error'].previousValue) {
 | 
			
		||||
        this.errorChange.emit(this.error);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Directive()
 | 
			
		||||
@ -88,6 +109,7 @@ export abstract class _ToggleBase extends PageComponent implements AfterContentI
 | 
			
		||||
 | 
			
		||||
  ngAfterContentInit(): void {
 | 
			
		||||
    this.toggleOptions.changes.pipe(startWith(null), takeUntil(this._destroyed)).subscribe(() => {
 | 
			
		||||
      this.subscribeToToggleOptions();
 | 
			
		||||
      this.syncToggleHeaderOptions();
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
@ -97,13 +119,26 @@ export abstract class _ToggleBase extends PageComponent implements AfterContentI
 | 
			
		||||
    this._destroyed.complete();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private subscribeToToggleOptions() {
 | 
			
		||||
    this.toggleOptions.forEach(option => {
 | 
			
		||||
      if (isDefinedAndNotNull(option.error) || isDefinedAndNotNull(option.errorText)) {
 | 
			
		||||
        option.errorChange.pipe(takeUntil(this._destroyed)).subscribe(() => {
 | 
			
		||||
          this.syncToggleHeaderOptions();
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private syncToggleHeaderOptions() {
 | 
			
		||||
    if (this.toggleOptions?.length) {
 | 
			
		||||
      this.options.length = 0;
 | 
			
		||||
      this.toggleOptions.forEach(option => {
 | 
			
		||||
        this.options.push(
 | 
			
		||||
          { name: option.viewValue,
 | 
			
		||||
            value: option.value
 | 
			
		||||
          {
 | 
			
		||||
            name: option.viewValue,
 | 
			
		||||
            value: option.value,
 | 
			
		||||
            error: option.error,
 | 
			
		||||
            errorText: option.errorText
 | 
			
		||||
          }
 | 
			
		||||
        );
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
@ -7980,7 +7980,8 @@
 | 
			
		||||
                "trips": "Trips",
 | 
			
		||||
                "markers": "Markers",
 | 
			
		||||
                "polygons": "Polygons",
 | 
			
		||||
                "circles": "Circles"
 | 
			
		||||
                "circles": "Circles",
 | 
			
		||||
                "required-fields": "Required fields are not filled in."
 | 
			
		||||
            },
 | 
			
		||||
            "data-layer": {
 | 
			
		||||
                "source": "Source",
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user