{"id":2889,"date":"2023-09-26T23:46:14","date_gmt":"2023-09-26T21:46:14","guid":{"rendered":"https:\/\/nguenkam.com\/blog\/?p=2889"},"modified":"2023-09-26T23:46:14","modified_gmt":"2023-09-26T21:46:14","slug":"how-to-detect-clicks-outside-the-element-in-angular-16","status":"publish","type":"post","link":"https:\/\/nguenkam.com\/blog\/index.php\/2023\/09\/26\/how-to-detect-clicks-outside-the-element-in-angular-16\/","title":{"rendered":"How to detect clicks outside the Element in Angular 16"},"content":{"rendered":"\n<p>In Angular, directives are defined as classes that can add new behavior to the elements in the template or modify existing behavior.<\/p>\n\n\n\n<p>The purpose of directives in Angular is to maneuver the\u00a0<a rel=\"noreferrer noopener\" href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Document_Object_Model\" target=\"_blank\">DOM<\/a>\u00a0(Document Object Model),whether by adding new elements to the DOM or removing elements and even changing the appearance of the DOM elements.<\/p>\n\n\n\n<p>There are three types of directives:<\/p>\n\n\n\n<ul><li><strong>Attribute directives<\/strong> : enable Angular developers to define an attribute that, when added to an element change the appearance of the element or enhances its functionality.For example, ngStyle( applying styles) or ngClass(applying\u00a0<a rel=\"noreferrer noopener\" href=\"https:\/\/www.simplilearn.com\/tutorials\/css-tutorial\" target=\"_blank\">CSS<\/a>\u00a0classes).<\/li><li>\u00a0<strong>Structural directives<\/strong>:  enable Angular developers to add, edit, and remove elements in the DOM. An example would be <span class=\"has-inline-color has-vivid-cyan-blue-color\"><strong>*ngIf<\/strong><\/span>(adding or removing element from DOM) or<span class=\"has-inline-color has-vivid-cyan-blue-color\"><strong> *ngFor<\/strong><\/span>(lists elements of every iteration).<\/li><li><strong>Component directives<\/strong>: this type of directive has a template or template URLs. In effect, it is a component directive that shows something in DOM.<\/li><\/ul>\n\n\n\n<p>Sometimes, in Angular, we have a situation where we need to detect the outside click of an element inside our Web application. For example, close some dialog when we click outside the dialog container on the user interface.<\/p>\n\n\n\n<p>For this kind of purposes, we can create a specific attribute directive.<\/p>\n\n\n\n<p>This directive will use only\u00a0<a rel=\"noreferrer noopener\" href=\"https:\/\/angular.io\/api\/core\" target=\"_blank\">Angular core<\/a>\u00a0stuff like directives, output, host listener decorators, and event emitters.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import { \r\n  Directive, \r\n  ElementRef, \r\n  EventEmitter, \r\n  HostListener, \r\n  Output \r\n} from '@angular\/core';\r\n\r\n@Directive({\r\n  selector: '&#91;appClickOutside]'\r\n})\r\nexport class ClickOutsideDirective {\r\n\r\n  @Output() \r\n  appClickOutside: EventEmitter&lt;void> = new EventEmitter();\r\n\r\n  @HostListener('document:click', &#91;'$event']) \r\n  onDocumentClick(event: PointerEvent) {\r\n    const nativeElement: any = this.elementRef.nativeElement;\r\n    const clickedInside: boolean = nativeElement.contains(event.target);\r\n    if (!clickedInside) {\r\n      this.appClickOutside.emit();\r\n    }\r\n  }\r\n\r\n  constructor(private elementRef: ElementRef) { }\r\n\r\n}<\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<p>So, we have a class marked with a directive decorator. Notice that we have the same name for the directive selector and the directive output event name. In this way, we can use directives on the template as one line later.<\/p>\n\n\n\n<p>The host listener is the function decorator responsible for executing a specific event handler with input parameters for a specific DOM event.<\/p>\n\n\n\n<p>So, we are listening here for a click event on document level, and we are passing the whole event object (the pointer event object) to the document click handler.<\/p>\n\n\n\n<p>Inside the click handler, we are checking if the event target element is not present inside the native element (the element where the directive is added), and only in that case are we using the click event emitter to emit the event without any parameters.<\/p>\n\n\n\n<p>And now we can use the directive inside a simple component with an Angular logo image:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import { Component, OnInit } from '@angular\/core';\r\nimport { DomSanitizer, SafeResourceUrl } from '@angular\/platform-browser';\r\n\r\n@Component({\r\n  selector: 'app-click-outside-test',\r\n  template: `\r\n    &lt;ng-container>\r\n    &lt;img\r\n      (appClickOutside)=\"onOutsideImgClick()\"\r\n      width=\"40\"\r\n      alt=\"Angular Logo\"\r\n      &#91;src]=\"ngLogoImgSrc\"\r\n    \/>\r\n    &lt;\/ng-container>\r\n  `\r\n})\r\nexport class ClickOutsideTestComponent {\r\n\r\n  ngLogoImgSrc: SafeResourceUrl;\r\n  ngLogoBase64: string = `\r\n    data:image\/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwM\r\n    C9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEi\r\n    IGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQ\r\n    uMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLj\r\n    ItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZ\r\n    mlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJo\r\n    NDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQ\r\n    wLjl6IiAvPgogIDwvc3ZnPg==\r\n  `;\r\n\r\n  constructor(private domSanitizer: DomSanitizer) {\r\n    this.ngLogoImgSrc = this\r\n      .domSanitizer\r\n      .bypassSecurityTrustResourceUrl(this.ngLogoBase64);\r\n  }\r\n\r\n  onOutsideImgClick() {\r\n    console.log('Clicked outside img element');\r\n  }\r\n}<\/code><\/pre>\n\n\n\n<p>Now we are rendering the test component inside the app component responsible for bootstrapping the whole application:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import { Component } from '@angular\/core';\r\n\r\n@Component({\r\n  selector: 'app-root',\r\n  template: `\r\n    &lt;div class=\"toolbar\" role=\"banner\">\r\n      &lt;app-click-outside-test>&lt;\/app-click-outside-test>\r\n      &lt;span>Welcome&lt;\/span>\r\n    &lt;\/div>\r\n    &lt;router-outlet>&lt;\/router-outlet>\r\n  `,\r\n  styles: &#91;`\r\n    :host {\r\n      font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\";\r\n      font-size: 14px;\r\n      color: #333;\r\n      box-sizing: border-box;\r\n      -webkit-font-smoothing: antialiased;\r\n      -moz-osx-font-smoothing: grayscale;\r\n    }\r\n\r\n    .toolbar {\r\n      position: absolute;\r\n      top: 0;\r\n      left: 0;\r\n      right: 0;\r\n      height: 60px;\r\n      display: flex;\r\n      align-items: center;\r\n      background-color: #1976d2;\r\n      color: white;\r\n      font-weight: 600;\r\n    }\r\n\r\n    .toolbar img {\r\n      margin: 0 16px;\r\n    }\r\n  `]\r\n})\r\nexport class AppComponent {\r\n  title = 'ng16';\r\n}<\/code><\/pre>\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h5>Reference:<\/h5>\n\n\n\n<p><a href=\"https:\/\/levelup.gitconnected.com\/\">https:\/\/levelup.gitconnected.com\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In Angular, directives are defined as classes that can add new behavior to the elements in the template or modify existing behavior. The purpose of directives in Angular is to maneuver the\u00a0DOM\u00a0(Document Object Model),whether by adding new elements to the DOM or removing elements and even changing the appearance of the DOM elements. There are [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":1965,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[37],"tags":[736,734,397,87,735],"_links":{"self":[{"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/posts\/2889"}],"collection":[{"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/comments?post=2889"}],"version-history":[{"count":1,"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/posts\/2889\/revisions"}],"predecessor-version":[{"id":2890,"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/posts\/2889\/revisions\/2890"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/media\/1965"}],"wp:attachment":[{"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/media?parent=2889"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/categories?post=2889"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/tags?post=2889"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}