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

How to define an index signature in Typescript that includes both mandatory and optional keys

I am on a quest to discover a more refined approach for creating a type that permits certain keys of its index signature to be optional. Perhaps this is a scenario where generics would shine, but I have yet to unlock the solution. At present, my construc ...

Long loading times observed for larger datasets in Angular4 Datatable

I am currently experiencing slow loading times for my datatable when trying to display the data. The script is being called within the component like so: ngAfterViewInit() { $.getScript('./assets/js/datatables/datatable-basic.js'); } T ...

Upgrading from Angular 5 to Angular 7: A seamless migration journey

Following my migration from Angular 5 to Angular 7, I encountered an issue with RxJs operations such as observables and @ngrx/store. Here is the error message I received: ERROR in node_modules/@ngrx/store/src/actions_subject.d.ts(2,10): error TS2305: Mo ...

Working with TypeScript: Overriding a Parent Constructor

I am new to TypeScript and currently learning about Classes. I have a question regarding extending parent classes: When we use the extends keyword to inherit from a parent class, we are required to call the super() method in the child class constructor. H ...

The Fuel-ui module in Angular 2 fails to function properly when loaded from a different directory

We recently switched from ng-cli to Gulp for building our Angular2 project, and we are utilizing Fuel-ui. An unusual error has come up. We have incorporated Fuel-ui's alert component into one of our components. When referencing fuel-ui from node_mo ...

What is the process for accessing my PayPal Sandbox account?

I'm having trouble logging into my SandBox Account since they updated the menu. The old steps mentioned in this post Can't login to paypal sandbox no longer seem to work. Could someone please provide me with detailed, step-by-step instructions o ...

Is there a way to enforce a mandatory lambda argument?

I am trying to pass a lambda into a function, but I need the lambda to have only one argument. TypeScript correctly generates an error if I provide two parameters to the lambda, however it does not raise any issues if I leave out any arguments altogether ...

Dealing with undefined arrays in Angular across multiple templates: Best practices

I'm currently developing a search screen for an application and I've come up with three possible outcomes for the results section. If the user hasn't searched yet, then show nothing. If the user searches and the array is empty, display "no ...

Having trouble getting combineLatest to properly normalize data in Angular using RxJS

Difficulty arose when attempting to normalize data prior to merging it into a new stream, resulting in no changes. I need to verify whether the user has liked the post using a Promise function before including it in the Posts Observable. this.data$ = comb ...

Implement the click event binding using classes in Angular 2

If I have the template below, how can I use TypeScript to bind a click event by class? My goal is to retrieve attributes of the clicked element. <ul> <li id="1" class="selectModal">First</li> <li id="2" class="selectModal">Seco ...

Executing Promises in TypeScript Sequentially

I have a collection of doc objects and I need to send an API request for each doc id in the list, executing the requests in a sequential manner. In my Typescript code, I am using Promise.all and Promise.allSelected to achieve this. [ { "doc_id&q ...

Having difficulty accessing the 'makeCurrent' property of an undefined object in Angular mobile application

I have followed the steps outlined in the Angular mobile toolkit guide found at https://github.com/angular/mobile-toolkit/blob/master/guides/cli-setup.md My Node version is v4.4.3 NPM version is 2.15.1 The issue arises when I run the command $ ng serve, ...

What is the process for invoking a microservice (constructed in express js) from an angular application that is currently communicating with a sails js backend?

I had initially developed an application with Angular frontend and Sails JS backend. However, I recently separated some of the backend functions into a micro-service using Express. Now, I am looking for guidance on how to call these functions from my mai ...

Choosing options using an enum in Angular 2

In my TypeScript code, I have defined an enum called CountryCodeEnum which contains the values for France and Belgium. export enum CountryCodeEnum { France = 1, Belgium = 2 } Now, I need to create a dropdown menu in my form using this enum. Each ...

What is the correct method for importing a Node module into Angular using TypeScript or AngularCLI?

As I integrate some "legacy" (non-typescript) JavaScript libraries into my Angular single page application. Usually, I simply include a CDN link in the index.html file like this: <script src="//cdnjs.cloudflare.com/ajax/libs/pako/1.0.6/pako.min.js"> ...

Different types of subscriptions for forkJoin observable

I am currently making two API requests with typed responses and combining them using the Observable.forkJoin method. My goal is to store each of the results in separate typed variables. var observableOrganization: Observable<Organization> = this.get ...

Achieving a Subset Using Functional Programming

Looking for suggestions on implementing a function that takes an array A containing n elements and a number k as input. The function should return an array consisting of all subsets of size k from A, with each subset represented as an array. Please define ...

Enhance Vue TypeScript components with custom component-level properties

In my vue2 project, I am utilizing vue-class-component along with vue-property-decorator. My goal is to implement component-level security validation for each component when it loads. I imagine implementing it with a signature like this: @Component @Secur ...

Typescript challenge: Implementing a route render attribute in React with TypeScript

My component has props named project which are passed through a Link to a Route. Here's how it looks (the project object goes in the state extended property): <Link to={{ pathname: path, state: { project, }, }} key={project. ...

Having trouble with the lodash find function in my Angular application

npm install lodash npm install @types/lodash ng serve import { find, upperCase } from 'lodash'; console.log(upperCase('test')); // 'TEST' console.log(find(items, ['id', id])) // TypeError: "Object(...)(...) is un ...