Ways to implement modifications to two separate input fields utilizing a single function

I am in the process of developing a performance comparison widget using Angular. The purpose of this widget is to compare the performance of the current Calendar year with the Previous Calendar Year, as well as the performance from the current Year-to-date with the Previous Year-to-date. All the necessary mathematical calculations will be taken care of by me. I have also created a stackblitz for demonstration purposes. Allow me to elaborate on the code structure. I have implemented two dropdowns using basic HTML elements select and option. Additionally, there is another component called app-monthpicker, which serves a specific purpose:

https://i.sstatic.net/V8yCf.png

Both dropdown menus are populated with options from the same array defined in typescript:

modes = ['Calendar Year', 'Year to date'];

Furthermore, each option has a predefined time range associated with it:

  1. For the Calendar year mode, the range spans from '01-01-2020' to '12-31-2020';
  2. For the Year-to-date mode, the range extends from '01-01-2020' to '02-07-2020';

The ranges mentioned above are hardcoded within the app-monthpicker component.

Both dropdowns are linked to the same variable. Below is the relevant code snippet:

<div class="inner-panel">
  <h3>Time selection widget</h3>
  Primary:<br>
  <select [(ngModel)]="primaryMode" (change)="modeChangeHandler($event)">
    <option *ngFor="let mode of modes" [ngValue]="mode">{{mode}}</option>
  </select>
  <br><br>
  <app-monthpicker></app-monthpicker>
  <br><br>
  Secondary:<br>
  <select [(ngModel)]="secondaryMode" (change)="modeChangeHandler($event)">
    <option *ngFor="let mode of modes" [ngValue]="mode">Previous {{mode}}</option>
  </select>
  <br><br>
  <app-monthpicker></app-monthpicker>
</div>

Below is the implementation of the method modeChangeHandler:

@ViewChild(MonthpickerComponent, {static: false}) monthpicker: MonthpickerComponent;

constructor() {}

ngOnInit(): void {
}

modeChangeHandler() {
    if (this.primaryMode === this.modes[0] || this.secondaryMode === this.modes[0]) {
        this.initCalendarYear();
    } else if (this.primaryMode === this.modes[1] || this.secondaryMode === this.modes[1]) {
        this.initYearToDate();
    } else {
      console.log("Default case");
    }
}

initCalendarYear() {
    this.monthpicker.startRange = '01-01-2020';
    this.monthpicker.endRange = '12-31-2020';
}

initYearToDate() {
    this.monthpicker.startRange = '01-01-2020';
    this.monthpicker.endRange = '02-07-2020';
}

My concern lies with the fact that the values in my secondary dropdown menu are not updating despite being bound to the same variables. Instead, the secondary dropdown menu is altering the range of the field above it rather than its intended range.

Answer №1

Using Angular template syntax and Ids can be a helpful solution.

To differentiate between the monthPickers, I included #primary and #secondary to specify them in the component for easy reference. Adding an id to both selectors allows for identification of the event target when triggered.

<div class="time-selector">
<p-overlayPanel class="my-overlay" #op>
    <br />
    <div class="inner-panel">
        <h3>Time selection widget</h3>
        Primary:<br>
        <select id="primarySelect" [(ngModel)]="primaryMode" (change)="modeChangeHandler($event)">
           <option *ngFor="let mode of modes" [ngValue]="mode">{{mode}}</option>
        </select>
        <br><br>
        <app-monthpicker #primary></app-monthpicker>
        <br><br>
        Secondary:<br>
        <select id="secondarySelect" [(ngModel)]="secondaryMode" (change)="modeChangeHandler($event)">
           <option *ngFor="let mode of modes" [ngValue]="mode">Previous {{mode}}</option>
        </select>
        <br><br>
        <app-monthpicker #secondary></app-monthpicker>
    </div>
</p-overlayPanel>

In the component, changes were made:

ViewChild was replaced with:

 @ViewChild("primary", { static: true }) primaryMonthPicker: MonthpickerComponent;
 @ViewChild("secondary", { static: true }) secondaryMonthPicker: MonthpickerComponent;

The event handler and functions called were updated to pass the target id for calendar updating.

 modeChangeHandler(event) {
    if (
      this.primaryMode === this.modes[0] ||
      this.secondaryMode === this.modes[0]
    ) {
      this.initCalendarYear(event.target.id);
    } else if (this.primaryMode === this.modes[1]) {
      this.initYearToDate(event.target.id);
    } else {
      console.log("Default case");
    }
  }

  initCalendarYear(target: string) {
    if (target === "primarySelect") {
      this.secondaryMonthPicker.startRange = "01-01-2020";
      this.primaryMonthPicker.endRange = "12-31-2020";
    } else if (target === "secondarySelect") {
      this.primaryMonthPicker.startRange = "01-01-2020";
      this.secondaryMonthPicker.endRange = "12-31-2020";
    }
  }

  initYearToDate(target: string) {
    if (target === "primarySelect") {
      this.primaryMonthPicker.startRange = "01-01-2020";
      this.primaryMonthPicker.endRange = "02-07-2020";
    } else if (target === "secondarySelect") {
      this.secondaryMonthPicker.startRange = "01-01-2020";
      this.secondaryMonthPicker.endRange = "02-07-2020";
    }
  }

Check out the full example @ StackBlitz

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

"Take control of FileUpload in PrimeNG by manually invoking it

Is there a way to customize the file upload process using a separate button instead of the component's default Upload button? If so, how can I achieve this in my code? Here is an example of what I've attempted: <button pButton type="button" ...

The key provided does not correspond to a constructor object

I have a unique method that implements an interface. This is My Command. import iCommand from './i-command'; export default class Voice implements iCommand { args: String[]; message: any; client: any; config: any; constructor(a ...

Creating a dynamic routerLink value in Angular 8 for items within an ngFor loop

I am currently attempting to route a dynamic value from the NgFor using [routerLink]. <li class="list-group-item d-flex justify-content-between align-items-center" *ngFor="let factors of factorsList"> <span>{{factors | ...

There has been no answer provided. Could this be due to being utilized in an asynchronous function that was not returned as a promise?

I encountered the following error message: Error: No response has been set. Is this being used in an async call that was not returned as a promise to the intent handler? at DialogflowConversation.response (/user_code/node_modules/actions-on-google/dis ...

Troubles arise when trying to compile Typescript and React with esbuild

I set out to create a new package and upload it to npm, starting with a demo package first. I began by using this repository as a foundation: https://github.com/wobsoriano/vite-react-tailwind-starter After that, I made updates to the build script: " ...

What impact does introducing a constraint to a generic type have on the inference process?

Let's take a look at this scenario: function identity<T>(arr: T[]) { return arr } identity(["a", "b"]) In the above code snippet, the generic type T is inferred as string, which seems logical. However, when we introduce a ...

Exploring Angular2: A Guide to Interpolating Expressions in Templates

Is it possible to interpolate different types of Javascript expressions? Along with displayed properties like object.property and short expressions such as {{1+1}}, what other valid Javascript expressions can be used for interpolation? ...

Error Message in Angular2 and ASP.NET: 'Window object is not defined'

As a relatively new Angular2 developer and a complete novice at integrating it into an ASP.NET Web Application, I encountered a peculiar error while attempting to build in debug mode within my Angular2 ASP.NET web application. Surprisingly, the same error ...

Type property is necessary for all actions to be identified

My issue seems to be related to the error message "Actions must have a type property". It appears that the problem lies with my RegisterSuccess action, but after searching on SO, I discovered that it could be due to how I am invoking it. I've tried so ...

Guidelines for Organizing Angular Interface Files and Implementing Custom Type Guards

In my Angular 2 project, I am utilizing Interfaces and have implemented User Defined Type Guards: grid-metadata.ts export interface GridMetadata { activity: string; createdAt: object; totalReps: number; updatedAt: object; } grid.service.ts ... ...

Preflight CORS error 403, yet my header is correctly set

Currently developing an Ionic app that communicates with an API on a web server for database operations. A similar project was completed in the past, and I copied the code from there, but it's not functioning as expected. Below are the headers config ...

Trigger the browser to refresh translation files following the deployment

Our Angular/Ionic app utilizes the ngx-translate/core package for translations, and is hosted on Firebase. With each new build and deployment, Angular automatically creates a hash for our js files to ensure the browser fetches the latest version when chang ...

A glitch was encountered during the execution of the ionic-app-scripts subprocess

I recently started using Ionic 3 and created an application that I'm trying to convert into an APK. To generate a debug (or testing) android-debug.apk file, I used the following CLI command: ionic cordova build android --prod The pages are declared ...

The width of Kendo Angular 2 grids pager and top header does not increase when scrolling

Our grids now have the horizontal scrolling feature enabled through CSS (kendo-grid {overflow: auto;}). However, we've noticed that the pager and top header of the grids do not expand their width when scrolling. Take a look at the screenshot below: ...

Unlock the power of Angular ViewChildren to access and manipulate SVG elements efficiently

I have an SVG file loaded as an object: <object data="assets/img/states.svg" type="image/svg+xml" id="map"></object> This SVG includes a large PNG map along with several rect and text elements. <rect y="224.72084" x="644.87109" ...

Transforming JSON data into an Angular TypeScript object

Delving into the realm of Angular on my own has been quite an enlightening journey, but I'm currently facing a specific issue: My aim is to create a website using both Spring for the back end and Angular 7 for the front end. However, I've encoun ...

Angular 2: Applying class to td element when clicked

I am working with a table structured like this <table> <tbody> <tr *ngFor="let row of createRange(seats.theatreDimension.rowNum)"> <td [ngClass]="{'reserved': isReserved(row, seat)}" id={{row}}_{{sea ...

Storing Bearer Tokens in Angular from Response Headers

After sending a login post request, I received a response. Everything looks good except the fact that the response body is empty and I am unsure how to access (and store locally) the Bearer token. Currently, this is what I can log: https://i.sstatic.net/N ...

Determine the value added tax in your online shopping basket

Currently, I am in the process of developing a webshop for a pizzeria using Angular, and recently completed work on my cart component. One of the key features I wanted to incorporate was adding a 10% Value-Added Tax (VAT) for each item in the cart and incl ...

Implementing a custom overwrite function in TypeScript's inheritance

Below is a class that I have: export class RestService { private baseUrl: string; constructor(protected http: HttpClient) { this.baseUrl = environment.LOCAL_URL; } public get<T>(resource: string, params?: HttpParams): Observable< ...