Angular 4/5 | Custom Dropdown Component

I have been working on a custom dropdown directive in Angular that I can attach to any DOM element. Below is the code for my directive:

import { Directive, HostListener } from '@angular/core';

@Directive({
  selector: '[appDropdown]'
})
export class DropdownDirective {

  constructor() { }

  isOpen: boolean = false;

  @HostListener('click') toggle() {
    if (this.isOpen === true) {
      this.hide();
    } else {
      this.show();
    }
    this.isOpen = !this.isOpen;
  }

  private show() {
    // Need help with what to implement here
  }

  private hide() {
    // Need help with what to implement here
  }

}

This directive is designed to respond to clicks on the element it is applied to. When a click event is detected, I want to toggle the visibility of the dropdown element within the same container as the element with the directive. A simplified version of the HTML structure is as follows:

<a appDropdown>Dropdown</a>
<ul class="dropdown"> <--- How can I manipulate the display property of this element when clicking the anchor to show/hide the dropdown?
   <li><a>Option A</a></li>
   <li><a>Option B</a></li>
</ul>

I have checked the Angular documentation thoroughly but couldn't find a clear solution. Any assistance would be greatly appreciated. Thank you!

Answer №1

From what I understand, directives are not meant to be used in this way. I am aiming for a similar result.

As I work on something similar and go through the documentation (and @evandro-mendes' response above), I realize that structural directives are intended to modify the DOM's behavior without defining their own templates (check out angular docs).

Refer to https://github.com/valor-software/ngx-bootstrap/blob/development/src/dropdown/bs-dropdown.directive.ts (or their docs/demo ) where a directive is used to display/hide/manipulate the component, but not to define its own content.

In my approach, using ngx-bootstrap, I create a component as shown below:

dropdown.component.ts:

@Component({
    selector: 'dropdown',
    template: './dropdown.component.html'
})
export class AutosuggestComponent {

    @Input() viewModel: string[];
    @Input() isOpen: boolean = false;
}

dropdown.component.html

<div dropdown [isOpen]="isOpen" [autoClose]="true" placement="top">

<ng-content #input>
</ng-content>

<div *dropdownMenu class="dropdown-menu" role="menu">
    <div *ngFor="let item of viewModel" class="dropdown-item">
        {{item}}
    </div>
</div>

usage

<dropdown [viewModel]="sourceData" [isOpen]="isDropdownOpen">
    <input type="text">
</dropdown>

This method allows me to avoid specifying any custom behavior and still utilize the dropdown for any input in the application.

I hope this explanation helps :)

Answer №2

In my opinion, it would be beneficial to incorporate certain Angular5 attributes.

To learn more about this, you can visit the following link:

Building An Angular 5 Project with Bootstrap 4 and Firebase

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

What is the best way to render images on the server side in React?

I've got this snippet of code residing in my server/server.js import path from 'path'; import fs from 'fs'; import React from 'react'; import ReactDOMServer from 'react-dom/server'; import express from 'ex ...

When uploading from Angular 2, PHP fails to populate the $_POST and $_FILES variables

I'm encountering difficulties when trying to upload files and data to my server using Angular 2 and PHP. After following the instructions in File Upload In Angular 2? to upload data and files from Angular 2, everything appears to be functioning corre ...

Strategies for resolving type issues in NextJs with Typescript

In my project using Next.js with TypeScript, I encountered an issue while trying to utilize the skipLibCheck = false property for enhanced checking. This additional check caused the build process to break, resulting in the following error: Error info - U ...

What is the subclass of all object literal types in TypeScript?

With the `strictFunctionTypes` setting turned on, function parameters are checked contravariantly. interface Func<T> { (p: T): unknown } declare let b: Func<{p1: string}> declare let c: Func<{p2: number}> declare let d: Func<{p3: nu ...

Displaying Photo on Webpage using Bearer Authorization Token in JavaScript

In my JavaScript code, I am currently loading an image using the following method: var img = new Image(); img.onload = function () { .. }; img.src = src; However, I have recently realized that I need to secure the images on my server side with OAuth 2, j ...

Resource Jump.js could not be loaded

Although I am still new to NPM, I have mostly built websites without using it. Recently, I decided to implement smooth scroll using Jump.js. Initially, everything seemed to work well when I used the live server extension in VScode. However, once I uploade ...

The functionality of the KendoReact Grid for filtering and sorting is not functioning correctly when data is grouped

Once I group the data, the filter and sort functions in the KendoReact Grid stop working. Interestingly, if I bypass the grouping step and show the data without grouping, the filter and sort functions function perfectly fine. My main objective is to figu ...

Error occurs when attempting to clear the cache storage

useEffect(async () => { caches.open('my-cache') }, [token, user_id]) Upon trying to log out of the application, const logoutFunc = () => { localStorage.clear() caches.keys().then((list) => list.map((key) => { ...

How to modify the content type in an Angular.js $http.delete request

When making a $http.delete request in my Angular app, I include a config object using the following approach: return $http.delete('projects/' + projectID + '/activityTypes', {data: [{id: 2}]}) This method attaches the values from my d ...

Troubleshoot: Issue with binding data from DynamicComponentLoader in Angular 2 template

My implementation involves the utilization of DynamicComponentLoader and is based on the Angular2 API Guide. https://angular.io/docs/ts/latest/api/core/DynamicComponentLoader-class.html The code structure I have set up looks like this: import {Page} fro ...

Elements in Motion

Working on a parallax effect, I've managed to assign unique scroll speeds to (almost) every element. Moreover, these elements are programmed not to activate their scroll speed until they enter the viewport. Below is the JavaScript code for trigger co ...

Struggling to access values from your model using EL in JavaScript? Let me provide some guidance

In my model, there is an object named "domain" with two methods: getDescriptionEn() and getDescriptionFr(). I am trying to retrieve the appropriate description based on the current locale. My issue lies in the following code snippet: var locale = "${cur ...

Avoiding repetitive logic in both parent and child components in Angular 8

In my parent controller, I have common requests and I also read router params for those requests. However, for the child components, I have different requests but still need to extract the same parameters from the router - resulting in duplicate code. For ...

When using res.redirect in Express, it not only redirects to a new URL but also allows you to access the HTML

I'm having an issue with redirecting a user to a login page when they click a button. Instead of being redirected, I am receiving the html source code and nothing is happening. My express redirect method is as follows: function customRedirect(req, ...

Converting a nested JavaScript array into a PHP array

Having a javascript array is how my dilemma starts: foodList = ([apple,10,],[banana,20]) To convert this to a json object and send it to php, I perform the following action: var jsonData = JSON.stringify(foodList); The challenge now is extracting values ...

Leverage promises to alter reactive data, strategically placing them to minimize the frequency of triggers being activated

Initial Method const list = reactive([1, 2, 3, 4, 5]); const clickHandler = () =>{ list.push(...[11, 12, 13, 14, 15]); list.push(...[16, 17, 18, 19, 20]); Promise.resolve().then(() => { list.push(33) ...

React/Typescript: The object might be null

I am currently converting a React component to TypeScript. The component is making an API call, and although I believe my interfaces are correctly set up, I seem to be passing the types incorrectly. How can I resolve the two errors in the Parent componen ...

Content within the Iframe is in the process of loading, followed by

Exploring the code below: <iframe id="myframe" src="..."></iframe> <script> document.getElementById('myframe').onload = function() { alert('myframe is loaded'); }; </script> Is it a possibility that the ifra ...

The dark theme in React Material UI will be specifically targeted and applied only to the drawer

I want to implement a dark theme specifically for the drawer component. In Drawer.js <ThemeProvider theme={theme}> <div> {props.token && ( <Drawer anchor="left" open={props.isDrawerOpen} ...

Angular Material: angular 4 alternative for detecting screen size greater than medium using $mdMedia('gt-md') function

Currently, I am working on integrating a sidenav into my web application with a focus on making it responsive. To accomplish this, I am utilizing Angular Material2 and Angular 4. <md-sidenav #sidenav layout="column" class="md-sidenav-left" md-component- ...