File

projects/angular/directives/ui-matformfield-required/src/ui-matformfield-required.directive.ts

Implements

AfterViewInit OnDestroy

Metadata

Index

Properties
Methods
Accessors

Constructor

constructor(_overlay: Overlay, _elemRef: ElementRef, _scrollDispatcher: ScrollDispatcher, _viewContainerRef: ViewContainerRef, _ngZone: NgZone, _platform: Platform, _ariaDescriber: AriaDescriber, _focusMonitor: FocusMonitor, _scrollStrategy: any, _dir: Directionality, _defaultOptions: MatTooltipDefaultOptions, _document: any, intl: UiMatFormFieldRequiredIntl)
Parameters :
Name Type Optional
_overlay Overlay No
_elemRef ElementRef No
_scrollDispatcher ScrollDispatcher No
_viewContainerRef ViewContainerRef No
_ngZone NgZone No
_platform Platform No
_ariaDescriber AriaDescriber No
_focusMonitor FocusMonitor No
_scrollStrategy any No
_dir Directionality No
_defaultOptions MatTooltipDefaultOptions No
_document any No
intl UiMatFormFieldRequiredIntl No

Methods

ngAfterViewInit
ngAfterViewInit()
Returns : void
ngOnDestroy
ngOnDestroy()
Returns : void

Properties

Public intl
Type : UiMatFormFieldRequiredIntl
Decorators :
@Optional()

Accessors

matControl
setmatControl(matControl: MatFormFieldControl)
Parameters :
Name Type Optional
matControl MatFormFieldControl<any> No
Returns : void
import {
    Subject,
    Subscription,
} from 'rxjs';
import {
    takeUntil,
    tap,
} from 'rxjs/operators';

import {
    AriaDescriber,
    FocusMonitor,
} from '@angular/cdk/a11y';
import { Directionality } from '@angular/cdk/bidi';
import { Overlay } from '@angular/cdk/overlay';
import { Platform } from '@angular/cdk/platform';
import { ScrollDispatcher } from '@angular/cdk/scrolling';
import { DOCUMENT } from '@angular/common';
import {
    AfterViewInit,
    ContentChild,
    Directive,
    ElementRef,
    Inject,
    NgZone,
    OnDestroy,
    Optional,
    ViewContainerRef,
} from '@angular/core';
import { MatFormFieldControl } from '@angular/material/form-field';
import {
    MatTooltip,
    MatTooltipDefaultOptions,
    MAT_TOOLTIP_DEFAULT_OPTIONS,
    MAT_TOOLTIP_SCROLL_STRATEGY,
} from '@angular/material/tooltip';

import { UiMatFormFieldRequiredIntl } from './ui-matformfield-required.directive.intl';

const MATFORMFIELD_LABEL_SELECTOR = '.mat-form-field-label-wrapper label';

@Directive({
    // eslint-disable-next-line @angular-eslint/directive-selector
    selector: `mat-form-field`,
})
export class UiMatFormFieldRequiredDirective implements AfterViewInit, OnDestroy {
    @ContentChild(MatFormFieldControl)
    set matControl(matControl: MatFormFieldControl<any>) {
        if (this._matControlSubscription) {
            this._matControlSubscription.unsubscribe();
        }
        this._matControlSubscription = matControl.stateChanges.pipe(
            takeUntil(this._destroyed$),
        ).subscribe(this._updateDisableTooltipProperty(matControl));
    }

    private _matControlSubscription?: Subscription;
    private _tooltip?: MatTooltip;
    private _labelElement?: HTMLElement;
    private _destroyed$ = new Subject<void>();

    constructor(
        private _overlay: Overlay,
        private _elemRef: ElementRef,
        private _scrollDispatcher: ScrollDispatcher,
        private _viewContainerRef: ViewContainerRef,
        private _ngZone: NgZone,
        private _platform: Platform,
        private _ariaDescriber: AriaDescriber,
        private _focusMonitor: FocusMonitor,
        @Inject(MAT_TOOLTIP_SCROLL_STRATEGY)
        private _scrollStrategy: any,
        @Optional()
        private _dir: Directionality,
        @Optional()
        @Inject(MAT_TOOLTIP_DEFAULT_OPTIONS)
        private _defaultOptions: MatTooltipDefaultOptions,
        @Inject(DOCUMENT)
        private _document: any,
        @Optional()
        public intl: UiMatFormFieldRequiredIntl) {
        this.intl = this.intl || new UiMatFormFieldRequiredIntl();
    }

    ngAfterViewInit() {
        // attach tooltip on the span, which is the parent of label
        this._labelElement = this._elemRef.nativeElement.querySelector(MATFORMFIELD_LABEL_SELECTOR)?.parentNode;

        if (this._elemRef.nativeElement.querySelector('[required]')
            && !this._elemRef.nativeElement.classList.contains('mat-form-field-disabled')) {
            this._createMatTooltip();
        }
    }

    ngOnDestroy() {
        this._destroyed$.next();
        this._destroyed$.complete();
    }

    private _updateDisableTooltipProperty(matControl: MatFormFieldControl<any>) {
        return () => {
            if (this._tooltip && (!matControl.required || matControl.disabled)) {
                this._tooltip.disabled = true;
            }
            if (matControl.required && !matControl.disabled) {
                if (this._tooltip) {
                    this._tooltip.disabled = false;
                } else {
                    this._createMatTooltip();
                }
            }
        };
    }

    private _createMatTooltip() {
        if (!this._labelElement) { return; }

        const labelElementRef = new ElementRef(this._labelElement!);
        // FIXME: should find another way to instantiate the MatTooltip
        // https://github.com/angular/angular/issues/8785
        this._tooltip = new MatTooltip(
            this._overlay,
            labelElementRef,
            this._scrollDispatcher,
            this._viewContainerRef,
            this._ngZone,
            this._platform,
            this._ariaDescriber,
            this._focusMonitor,
            this._scrollStrategy,
            this._dir,
            this._defaultOptions,
            this._document,
        );

        this._tooltip.message = this.intl.tooltipMessage;
        // eslint-disable-next-line @angular-eslint/no-lifecycle-call
        this._tooltip.ngAfterViewInit();

        this.intl.changes.pipe(
            tap(() => this._tooltip!.message = this.intl.tooltipMessage),
            takeUntil(this._destroyed$),
        ).subscribe();
    }
}

results matching ""

    No results matching ""