Close action menu item for table row in Angular

436 views Asked by At

I have the following code for opening and closing a slide menu for each row in the table. The <td> is as shown below:

<td class="rm-release_table-cell" *ngIf="settings.actions">
                            <div>
                                <a id="release-action" href="javascript:void(0)" (click)="openAction($event)">
                                    <i class="material-icons">more_vert</i>
                                </a>
                                <div class="rm-release_action-layout hidden" #actionSlide id="release-{{release[settings.columns[0].field]}}">
                                    <div class="rm-release_action-container animate__animated" #actionContainer>
                                        <div class="d-flex align-items-center justify-content-between rm-release_action-header">
                                            <a class="rm-release_action-close" href="javascript:void(0)" (click)="closeAction($event)">
                                                <i class="material-icons">close</i>
                                            </a>
                                        </div>
                                        <div class="rm-release_action-item-layout">
                                            <div class="rm-release_action-item-layout">
                                                <ng-container *ngIf="release.permitted_actions;else actionMenu">
                                                    <ng-container *ngFor="let action of settings.actions">
                                                        <div *ngIf="release.permitted_actions.includes(action.action)" class="d-flex align-items-center rm-release_action-item" (click)="onAction(action.action, release)">
                                                            <i class="material-icons">{{action.icon}}</i>
                                                            <p>{{action.title}}</p>
                                                        </div>
                                                    </ng-container>
                                                </ng-container>
                                                <ng-template #actionMenu>
                                                    <ng-container *ngFor="let action of settings.actions">
                                                        <div class="d-flex align-items-center rm-release_action-item" (click)="onAction(action.action, release)">
                                                            <i class="material-icons">{{action.icon}}</i>
                                                            <p>{{action.title}}</p>
                                                        </div>
                                                    </ng-container>
                                                </ng-template>
                                            </div>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </td>

and the code in the component file is as shown below :

/**
     *
     * @param event
     */
    public openAction(event) {
        const parent = this.renderer.parentNode(event.target);
        const containerRef = this.renderer.nextSibling(parent);
        //second parent
        let elements = this.elem.nativeElement.querySelectorAll('.rm-release_action-layout');
        _.forEach(elements, function (element) {
            if (element.id != containerRef.id) {
                element.classList.add('hidden');
            } else {
                element.style.height = 'auto';
                element.style.width = '12rem';
                element.style.padding = '0.5rem'
            }
            // this.elem.nativeElement.classList.add('hidden');
            // this.renderer.addClass(element, 'hidden');
        });
        //third parent
        let parentElements = this.elem.nativeElement.querySelectorAll('.rm-release_action-container');
        _.forEach(parentElements, function (parentElement) {
            const parentNode = parentElement.parentNode;
            if (parentNode.id == containerRef.id) {
                parentNode.style.height = 'auto';
                parentNode.style.width = '12rem';
                parentNode.style.padding = '0.5rem';
            }
        });

        //const containerRef = this.renderer.nextSibling(parent);
        const containerChild = containerRef.children[0];

        this.renderer.removeClass(containerRef, "hidden");

        setTimeout(() => {
            this.renderer.setStyle(containerRef, "height", "auto");
            this.renderer.setStyle(containerRef, "width", "12rem");
            this.renderer.setStyle(
                containerRef,
                "padding",
                "0.5rem"
            );
        }, 100);

        setTimeout(() => {
            this.renderer.removeClass(containerChild, "hidden");
        }, 600);
        this.renderer.addClass(containerChild, 'animate__fadeIn');
    }

    /**
     *
     * @param event
     */
    public closeAction(event) {
        var parent = this.renderer.parentNode(event.target);
        var firstParent = this.renderer.parentNode(parent);
        var secondParent = this.renderer.parentNode(firstParent);
        var thirdParent = this.renderer.parentNode(secondParent);

        setTimeout(() => {
            this.renderer.addClass(secondParent, 'hidden');
            this.renderer.setStyle(thirdParent, 'height', '0rem');
            this.renderer.setStyle(thirdParent, 'width', '0rem');
            this.renderer.setStyle(thirdParent, 'padding', '0rem');
        }, 50);

        setTimeout(() => {
            this.renderer.addClass(thirdParent, 'hidden');
        }, 500);
    }

Now this is showing the action menu and it is closing when I click on the close icon. I need to close this action menu when I click anywhere outside the opened element. How this can be done ? Thanks in advance

1

There are 1 answers

0
Dako patel On

Add class to DOM nodes of popup & outside of popup. Then just check if click event triggered on DOM part inside of popup or outside.

file.ts

import { Component, ElementRef, HostListener } from '@angular/core';
clicked: string = '';

 constructor(private elem: ElementRef) { }


@HostListener('document:click', ['$event'])
  DocumentClick(event: Event) {
    if (this.elem.nativeElement.contains(event.target))
      this.clicked = "inside";
    else
      this.clicked = "outside";
  }

file.html

<p>
  Click anywhere in the document and we will tell whether it was inside or outside of the component.
</p>
Clicked {{clicked}}

Example

https://stackblitz.com/edit/angular-hostlistener-clicked-inside-outside