Tips on selecting specific text from a drop-down menu

After struggling to find a solution for retrieving the text of a selected item from a dropdown, I decided to create a common directive. This directive would allow me to easily access the text for all dropdown items when used in my code. Below is the snippet of my implementation:

app.component.html

<hello name="{{ name }}"></hello>
<p>
    Start editing to see some magic happen :)
</p>

<div>
    <p>Text from directive: {{selectedText}} </p>
    <p>Data from Parent Component - {{selectedProp}}</p>
    <select [psSelectText]="'selectedText'"  name="selectedProp" [(ngModel)]="selectedProp" >
    <option value=""></option>
    <option *ngFor="let i of arrayList" value="{{i.value}}">{{i.text}}</option>
  </select>
</div>
<br>
<button (click)="hitMe()">Hit me</button>

Custom Directive:

import { Directive, ElementRef, HostListener, Input, SimpleChanges, OnChanges, Output, EventEmitter, ViewContainerRef } from '@angular/core';
import { NgModel } from '@angular/forms';
import { SelectText } from './select-text.model';

@Directive({
  selector: '[ngModel][psSelectText]',
  providers: [NgModel],
  host: {
    '(ngModelChange)': 'onInputChange($event)'
  }
})
export class PsSelectText implements OnChanges {
  @Input('psSelectText') selectedText: string;
  @Input('ngModel') selectedModel: NgModel;

  constructor(private el: ElementRef, public model: NgModel, private viewContainerRef: ViewContainerRef) { }


  ngOnChanges(changes: SimpleChanges) {
    console.log(this.el)
    if (changes.selectedModel) {
      // this.selectedText.valueAccessor.writeValue(changes.selectedModel.currentValue);
      setTimeout(() => {
        this.viewContainerRef['_view'].component[this.selectedText] =
          this.el.nativeElement.selectedOptions[0].text;
      }, 0);
    }
  }

  onInputChange(event) {
    // Only get selected change
  }
}

Initially, I achieved this by passing a single variable like [psSelectText]="'selectedText'", However, I now aim to pass an object property such as selectedText2.text. Here, I want the text of the dropdown item to be set to the selectedText2.text property within the directive.

In order to achieve this, I plan to pass the attribute in the following manner:

[psSelectText]="selectedText2.text"

Subsequently, I intend to set the text of the dropdown using this field selectedText2.text

Is there a way to accomplish this? Thank you for your assistance.

Specifically, the modification required here is shown below:

// The property "this.selectedText2.text" will be dynamically provided,
        this.viewContainerRef['_view'].component[this.selectedText2.text] =
          this.el.nativeElement.selectedOptions[0].text;

Demo: https://stackblitz.com/edit/angular-dropdown-selected-text

Answer №1

It seems like you are trying to achieve the following:

  • Passing an object to your directive instead of just plain text
  • Assigning a value on the screen based on the passed object through the directive

Please review this and confirm if this aligns with your requirements: https://stackblitz.com/edit/angular-wbu8us

The code for ps-select-text.directive.ts & app.component.html are provided below:

/* tslint:disable:member-ordering */
import { Directive, ElementRef, HostListener, Input, SimpleChanges, OnChanges, Output, EventEmitter, ViewContainerRef } from '@angular/core';
import { NgModel } from '@angular/forms';
import { SelectText } from './app.component';

@Directive({
  selector: '[ngModel][psSelectText]',
  providers: [NgModel],
  host: {
    '(ngModelChange)': 'onInputChange($event)'
  }
})
export class PsSelectText implements OnChanges {
  @Input('psSelectText') selectedText: SelectText;
  @Input('ngModel') selectedModel: NgModel;

  constructor(private el: ElementRef, public model: NgModel, private viewContainerRef: ViewContainerRef) { }


  ngOnChanges(changes: SimpleChanges) {
    /*
    console.log(this.el);
    console.log(this.selectedText);
    console.log(this.viewContainerRef['_view'].component);
    */
    
    if (changes.selectedModel) {
      // this.selectedText.valueAccessor.writeValue(changes.selectedModel.currentValue);
      setTimeout(() => {

        if (this.selectedText) {
          this.viewContainerRef['_view'].component.selectedText = "(from inside Directive)" + this.selectedText.stText;
        }

        // "this.selectedText" this property will come from dynamically,
          /* 
        this.viewContainerRef['_view'].component[this.selectedText] = 
          this.el.nativeElement.selectedOptions[0].stText;
          */
      }, 0);
    }
  }

  onInputChange(event) {
    // Only get selected change
  }
}


/*
Copyright 2017-2018 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license
*/
<hello name="{{ name }}"></hello>
<p>
Start editing to see some magic happen :)
</p>

<div>
<p>Come from directive: <mark>{{selectedText}}</mark> </p>
<p>Come from Parent Component [ngModel]: 
    <span *ngIf="selectedText2"> 
      v: <mark>{{selectedText2.stValue}}</mark> & 
      t: <mark>{{selectedText2.stText}}</mark> 
    </span> 
  </p>
<select [psSelectText]="selectedText2"  name="selectedProp" [(ngModel)]="selectedText2" >
    <option value=""></option>
    <option *ngFor="let i of arrayList" [ngValue]="i" >{{i.stText}}</option>
  </select>
</div>
<br>
<button (click)="hitMe()">Hit me</button>

Answer №2

The code provided demonstrates the usage of Angular directives and components within an HTML file.

HTML:

<hello name="{{ name }}"></hello>
<p>
    Start editing to see some magic happen :)
</p>

<div>
    <p>Come from directive: {{selectedText}} </p>
    <p>Come from Parent Component - {{selectedProp}}</p>
    <select [psSelectText]="'selectedText'"  name="selectedProp" [(ngModel)]="selectedProp" >
    <option value=""></option>
    <option *ngFor="let i of arrayList" value="{{i.value}}">{{i.text}}</option>
  </select>
</div>
<br>
<button (click)="hitMe()">Hit me</button>

DIRECTIVE:

import { Directive, ElementRef, HostListener, Input, SimpleChanges, OnChanges, Output, EventEmitter, ViewContainerRef } from '@angular/core';
import { NgModel } from '@angular/forms';
import { SelectText } from './select-text.model';

@Directive({
  selector: '[ngModel][psSelectText]',
  providers: [NgModel],
  host: {
    '(ngModelChange)': 'onInputChange($event)'
  }
})
export class PsSelectText implements OnChanges {
  @Input('psSelectText') selectedText: string;
  @Input('ngModel') selectedModel: NgModel;

  constructor(private el: ElementRef, public model: NgModel, private viewContainerRef: ViewContainerRef) { }


  ngOnChanges(changes: SimpleChanges) {
    console.log(this.el)
    if (changes.selectedModel) {
      setTimeout(() => {
        this.viewContainerRef['_view'].component[this.selectedText] =
          this.el.nativeElement.selectedOptions[0].text;
      }, 0);
    }
  }

  onInputChange(event) {
    // Only get selected change
  }
}

COMPONENT:

import { Component, OnInit } from '@angular/core';
import { SelectText } from './select-text.model';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  name = 'Angular';
  selectedProp: string;
  selectedText: any = "yellow";
  selectedText2: SelectText;
  arrayList: Array<any> = [];

  hitMe() {
    this.selectedProp = "2";
  }

  ngOnInit() {
    // this.selectedText = new SelectText();    
    this.arrayList.push({ value: 1, text: "First Value" });
    this.arrayList.push({ value: 2, text: "Second Value" });
    this.arrayList.push({ value: 3, text: "Third Value" });
    this.arrayList.push({ value: 4, text: "Fourth Value" });
    this.arrayList.push({ value: 5, text: "Fifth Value" });
  }
}

DEMO:

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

Tips for creating Junit tests for a CDK environment

As a newcomer to CDK, I have the requirement to set up SQS infrastructure during deployment. The following code snippet is working fine in the environment: export class TestStage extends cdk.Stage { constructor(scope: cdk.Construct, id: string, props: ...

Angular Pagination: Present a collection of pages formatted to the size of A4 paper

Currently, I am working on implementing pagination using NgbdPaginationBasic in my app.module.ts file. import { NgbdPaginationBasic } from './pagination-basic'; My goal is to create a series of A4 size pages with a visible Header and Footer onl ...

Utilize a singular loader when simultaneously making numerous HTTP requests in Angular with ngx-ui-loader

After successfully implementing the ngx-ui-loader and setting the NgxUiLoaderHttpModule for all HTTP requests in my project, everything is working fine. However, I have encountered an issue on certain routes where multiple HTTP requests are being executed ...

Changing the name of a tab within a p-tabview

Setting up a p-tabview with tabs containing specific content involves the following code: <p-tabView class="tabmain" > <ng-container *ngFor="let tab of tabs"> <p-tabPanel [header]="tab.header" > ...

Effortless spring picture sharing thanks to @onetoonemapping

After uploading an image, I receive an image_id. However, when I use that id to upload a product, the product table shows an empty value in the image_id field. If you're unable to replicate the issue, you can access the code here. This is the struct ...

Encountering an error in Jest with TypeScript (Backend - Node/Express) that reads "Cannot use import statement outside a module

Currently, I am in the process of developing Jest tests for a Node/Express TypeScript backend. Recently, I came across the concept of global test setup which I am integrating to streamline the usage of variables and function calls that are repeated in all ...

Instructions on invoking a function from another Material UI TypeScript component using React

In this scenario, we have two main components - the Drawer and the AppBar. The AppBar contains a menu button that is supposed to trigger an event opening the Drawer. However, implementing this functionality has proven challenging. I attempted to use the li ...

In Angular, upon submitting the form, redirect to a separate component and display a message indicating the successful

I am facing an issue with a component that sends data to a service in order to save it in the database. Following this, I want to redirect or navigate to a different component and display a success message there. While I have implemented this functionality ...

Angular QR code scanner: Simplifying the process of scanning

Can anyone provide guidance on incorporating a Live QR Scanner into an Angular application? I attempted to use the Zxing library but struggling to find detailed documentation for integration with Angular. Your assistance is greatly appreciated. Thank you ...

Obtaining the value of dynamic checkboxes in Ionic 2

My goal is to populate checkboxes from a database and allow users to complete the checkbox form before submitting it back to the database. However, I am struggling to capture the values of dynamically populated checkboxes in my code snippet below. expor ...

What causes the discrepancy in errors when dealing with subtype versus regular assignments?

Below is a sample code that has been checked by TypeScript playground https://www.typescriptlang.org/play/ interface PartialCustomData { option?: number; } interface A { [key: string]: string | PartialCustomData; } interface B extends A { [k ...

Utilizing TypeScript to import and export modules under a single namespace

Have a look at this query that's quite similar to mine: https://github.com/Microsoft/TypeScript/issues/4529 Consider the following code snippet: //exported imports export {ISumanOpts, IGlobalSumanObj} from 'suman-types/dts/global'; export ...

Taking a segmented snapshot of a canvas using a flexible design scheme

I am working with a canvas that contains multiple div elements representing different sections of the canvas. However, when I capture these sections, they do not appear exactly as displayed on the screen. How can I track and accurately capture the div area ...

Programmatically click a button from the library by triggering a click on its outer div using Angular

Currently, I'm just starting out with Angular. I've been using the @abacritt/angularx-social-login package and noticed that the Google button it provides is only an icon. I'd like to customize its appearance by placing the icon inside a div ...

Setting up Storybook with Tailwindcss, ReactJS and Typescript: A comprehensive guide

What is the best way to configure Storybook to handle Tailwindcss styles and absolute paths? Just a heads up, this question and answer are self-documenting in line with this. It was quite the process to figure out, but I'm certain it will help others ...

Encountering Error with NodeJS Typescript: Issue with loading ES Module when running sls offline command

I have come up with a unique solution using NodeJS, Typescript, and Serverless framework to build AWS Lambdas. To debug it locally in VS Code, I use the serverless-offline library/plugin. You can find my project on GitHub here However, when I run the comm ...

Angular universal issue: 404 error code failing to function properly

After numerous attempts, I find myself at a dead end. Our Angular 11 website requires Universal for SEO purposes, and we have set up a 404 page to redirect when necessary. The issue arises when the redirect returns a status code of 200 instead of 404. To ...

Explain the interaction of cookies between Angular and C# controllers

Can anyone provide clarity on how cookies are utilized between an angular application and a C# server controller? After looking through various discussions and forums, here's what I've gathered: The angular client initiates an HTTP Request (e. ...

Error message received: "ReferenceError: document is not defined when attempting to utilize Angular 8 NgxUsefulSwiper

The NgxUsefulSwiper library is being used in a component and works fine on the local environment. However, upon trying to access the page with the component on the development environment, the following error occurs: ReferenceError: document is not defin ...

Getting a list of the stack resources available in cloudformation using TypeScript

My team is developing an application that will deploy multiple stacks to AWS. One of these stacks is called SuperStar, and it can only exist once per AWS account. I am currently exploring how our TypeScript CDK can retrieve a list of stacks from CloudFor ...