Encountering issues with an Angular directive when attempting to implement addEventListener while restructuring the functions

After creating a directive to enable a drop-down menu on my header, I encountered an issue. Rather than utilizing the hostListeners property on the @Directive decorator, I opted to implement it using vanilla JavaScript. Initially, the code functioned correctly. However, after refactoring the functions as standalone functions instead of anonymous functions, the functionality broke.

import { Directive, OnInit, ElementRef, OnDestroy } from '@angular/core';

@Directive({
    selector: '[headerDropdown]'
})
export class HeaderDropdownDirective implements OnInit, OnDestroy {

    private isActive: boolean;
    private isAbove: boolean;

    private dropDownElement: Element;
    private downArrowElement: Element;

    constructor(private elementRef: ElementRef) { }

    ngOnInit() {
        this.dropDownElement = document.querySelector('.header__dropdown');
        this.downArrowElement = this.elementRef.nativeElement;

        this.downArrowElement.addEventListener('mouseenter', this.downArrowOnMouseEnter);
        this.downArrowElement.addEventListener('mouseleave', this.downArrowOnMouseLeave);
        this.downArrowElement.addEventListener('click', this.downArrowOnClick);
        document.addEventListener('click', this.documentOnClick);
    }

    ngOnDestroy() {
        // TODO: removeEventListener
    }

    private activate() {
        this.isActive = true;
        this.downArrowElement.classList.add('header__item--active');
        this.dropDownElement.classList.add('header__dropdown--active');
    }

    private deActivate() {
        this.isActive = false;
        this.downArrowElement.classList.remove('header__item--active');
        this.dropDownElement.classList.remove('header__dropdown--active');
    }

    private downArrowOnMouseEnter() {
        this.isAbove = true;
    }

    private downArrowOnMouseLeave() {
        this.isAbove = false;
    }

    private downArrowOnClick() {
        if (!this.isActive) {
            this.activate();
        } else {
            this.deActivate();
        }
    }

    private documentOnClick() {
        if (!this.isAbove) {
            this.deActivate();
        }
    }

}

When interacting with the downArrow button, I encounter the following error:

EXCEPTION: this.activate is not a function
ErrorHandler.handleError @ VM12616:55
next @ VM12615:374
schedulerFn @ VM12630:100
SafeSubscriber.__tryOrUnsub @ VM12634:236
SafeSubscriber.next @ VM12634:185
...

<p>However, modifying the code like this resolves the issue:</p>

<pre><code>import { Directive, OnInit, ElementRef, OnDestroy } from '@angular/core';

@Directive({
    selector: '[headerDropdown]'
})
export class HeaderDropdownDirective implements OnInit, OnDestroy {

    private isActive: boolean;
    private isAbove: boolean;

    private dropDownElement: Element;
    private downArrowElement: Element;

    constructor(private elementRef: ElementRef) { }

    ngOnInit() {
        this.dropDownElement = document.querySelector('.header__dropdown');
        this.downArrowElement = this.elementRef.nativeElement;

        this.downArrowElement.addEventListener('mouseenter', () => { this.isAbove = true; });
        this.downArrowElement.addEventListener('mouseleave', () => { this.isAbove = false; });

        this.downArrowElement.addEventListener('click', () => {
            if (!this.isActive) {
                this.activate();
            } else {
                this.deActivate();
            }            
        });

        document.addEventListener('click', () => {
            if (!this.isAbove) {
                this.deActivate();
            }            
        });
    }

    ...

}

I have attempted changing the access level of the functions to public, but the problem persists with the same error message.

Answer №1

Modify

this.downArrowElement.addEventListener('mouseenter', this.downArrowOnMouseEnter);
this.downArrowElement.addEventListener('mouseleave', this.downArrowOnMouseLeave);
this.downArrowElement.addEventListener('click', this.downArrowOnClick);
document.addEventListener('click', this.documentOnClick);

as follows:

this.downArrowElement.addEventListener('mouseenter', this.downArrowOnMouseEnter.bind(this));
this.downArrowElement.addEventListener('mouseleave', this.downArrowOnMouseLeave).bind(this);
this.downArrowElement.addEventListener('click', this.downArrowOnClick.bind(this));
document.addEventListener('click', this.documentOnClick.bind(this));

Your reference to this does not pertain to the directive within these functions.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How can I access the keys with incorrect values in the JSON data using Angular 5 or TypeScript?

Is there a way to extract the keys with false values within this specified JSON? xyz: any = { abc: { 'a': true, 'b': true, 'c': true, 'd': false, 'e': { 'f&ap ...

Is there a way to set a custom port number for an Angular application?

I am currently in the process of constructing an Angular application. The application is designed to communicate with a server via HttpClient. However, each time the application connects to the server, it utilizes a different port. I am interested in confi ...

Leverage TypeScript to restrict the payload type based on the action name

Utilizing React's useReducer with TypeScript, I am facing an issue where I need to ensure that when the action type is 'SET', the payload has to be an array, and when the action type is 'ADD', the payload should be an object. Here ...

Struggling with getting autocomplete and auto import to work properly while working on an Angular project

After installing the latest version of VSCode on my Windows system, I proceeded to add language support for TypeScript and configure my editor settings by adjusting the font size, disabling the minimap, enabling autosave on focus change, and more. Addition ...

Issue connecting database with error when combining TypeORM with Next.js

I am attempting to use TypeORM with the next.js framework. Here is my connection setup: const create = () => { // @ts-ignore return createConnection({ ...config }); }; export const getDatabaseConnection = async () => { conso ...

What is the best way to set the index value as the id for a div element?

Currently I am working with Angular 2.0 and have an array named addExtra: number[] = [0,1,2,3];. This is the HTML code I am using: <div *ngFor="let val of addExtra"> <div class="row"> <div style="margin- ...

Challenges in conducting asynchronous tests for Angular2 due to setTimeout complications

Using Angular2.0.1, I encountered an issue while trying to write unit tests for an angular component that involved async tasks. This is a common scenario and even the latest testing examples from Angular include async tests (see here). My test kept failin ...

Can you help me transition my angular website from English to Spanish using a radio button?

I want to develop an Angular website where users can select a language and click the next button to change all text on subsequent pages to that chosen language. For example, if a user selects Spanish, then all text on the following screens will be in Spani ...

Despite the presence of a producer and topic, sending Kafka messages is proving to be a challenge

Currently, I am using TypeScript and the KafkaJS library on my local machine with a single Kafka broker. After successfully connecting a producer, confirming the creation of my topic, and creating messages like so: const changeMessage = { key: id, ...

Angular 5/6: Issue detected - mat-form-field must have a MatFormFieldControl inside

I'm experiencing an issue while trying to open an OpenDialog window from a table list. The error message I encountered is as follows: ERROR Error: mat-form-field must contain a MatFormFieldControl. Below is the HTML code for the openDialog: <h2 m ...

At what point does Angular's HttpClient.get() promise face potential rejection?

Within our Angular codebase, we often manage http requests in the following manner: return this.http .get<Whatever>(url) .toPromise() .then(response => { // handling successful response }) .catch(e => { // managing errors ...

Modify the value of a property in an array of objects using Angular within an HTML

I am working with an object structure like this: class FileData { file: File; description: string; } Within my components.ts file, I have an array of FileData objects of varying lengths. The corresponding component.html code looks like this: < ...

Unlocking the Power of Typescript in Your Laravel Mix and Vue SFC Workflow

Can Typescript be used in Vue single file components (SFC) with Laravel Mix? If so, how can this setup be implemented? The current setup includes Laravel Mix 5.0, Typescript 3.7.5, and Vue 2.5.17. A sample single file component written in Typescript is ...

Bidirectional data binding in Angular 2: Establishing seamless communication between components through a

I am facing an issue where I want to pass an object from a component to a service and then fetch it in another component as an observable. The idea is that any changes made in the Question Component should automatically update the Service. However, at pres ...

The error thrown is: Module 'typeorm' not found

Whenever I attempt to execute the (.exe) file of my ElectronJS project that was created using Angular, I keep encountering this specific error. What steps should I take in order to resolve this issue? ...

`Unable to access variable within the HTML file of a component in Angular`

I have been attempting to show the data from an array (which is populated in chat.component).. public matchesList = []; loadMatches() { ... if (result.success) { this.matchesList = result.matches_list.split(','); console.log(thi ...

Proper Validation in Angular6: Preventing Empty Input Fields

I've been working with Angular and grappling with the challenge of validating input fields to prevent white spaces. I decided to experiment with an IF statement, as shown below. Everything seemed to be working smoothly until I encountered an error mes ...

The attribute 'title' is not found in the data type 'Projects[]'

When attempting to retrieve data from a specific link, I encounter error TS2339: Property 'title' does not exist on type 'Projects[]', despite the presence of the 'title' property in 'Projects'. The goal is to access ...

Utilizing RouterLink along with a button and conditional rendering in Angular

One issue I am facing is using *ngIf to navigate to a different page based on a variable. Despite having valid links, when I click on the button nothing happens. Here is the code snippet: <button mat-button > <span class=&quo ...

Hide react component by clicking it

There is a cookies component with a button labeled "I agree" that I want to use to close the component when clicked. However, I am facing an issue in getting this functionality to work. I understand that the onClick event on the button should trigger an ...