Initiate the input change event manually

Struggling with creating a custom counter input component where the input value is controlled by custom increment/decrement buttons.

Desired output:

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

Content projection will be used to expose the input for form usage and adding properties like a regular number input. Considering using a directive on the input:

<my-counter-input>
  <input [(ngModel)]="count" myInputRef />
</my-counter-input>

The component includes two buttons and a ng-content-slot:

<button (click)="decrement()">-</button>
<ng-content select="input"></ng-content>
<button (click)="increment()">+</button>

So far, all seems well. Interaction with the directive can be done using the @ContentChild decorator.

@Component({
  selector: 'my-counter-input',
  templateUrl: './counter-input.component.html',
  styleUrls: ['./counter-input.component.scss'],
})
export class CounterInputComponent {
  @ContentChild(InputRefDirective)
  public input: InputRefDirective;

  constructor() {}

  public increment() {
    this.input.increment();
  }
  public decrement() {
    this.input.decrement();
  }
}

An issue arises when trying to bind the value of the input element to the directive; neither the increment nor decrement method affects the native input value. Struggling with achieving a two-way binding on the native input value.

@Directive({
  selector: 'input [myInputRef]',
})
export class InputRefDirective {
  @HostBinding('type') readonly type = 'number';

  @HostBinding('value') value = 5;

  public increment() {
    this.value++;
  }
  public decrement() {
    this.value--;
  }
}

Uncertain on the next steps. How can the value of the native input be updated along with triggering the native change event?

Answer №1

Utilize the power of NgControl

A fundamental class that serves as the foundation for all FormControl-based directives. It establishes a connection between a FormControl object and a specific DOM element.

By injecting NgControl into a directive, the Angular DI framework automatically selects the closest form control directive for us. This allows us to dynamically set the value of the formControl.

import { Directive, HostBinding, AfterViewInit } from "@angular/core";
import { NgControl } from "@angular/forms";

@Directive({
  selector: "[appInput]"
})
export class InputDirective implements AfterViewInit {
  @HostBinding("type") readonly type = "number";

   value = 5;

  ngAfterViewInit(){
     setTimeout(()=>{this.control.control.setValue(this.value)})
  }

  constructor(private control: NgControl) {
    
  }

  public increment() {
    this.control.control.setValue(this.value++);
  }
  public decrement() {
    this.control.control.setValue(this.value--);
  }
}

View Forked Working Example

Answer №2

To ensure that the ngModel is updated both on initialization and with each change, you can use the following code snippets:

public increment() {
  this.value++;
  this.updateNgModel(this.value);
}

public decrement() {
  this.value--;
  this.updateNgModel(this.value);
}

private updateNgModel(value: number) {
  this.ngModel.update.emit(value);
}

Check out the code here for reference.

Answer №3

If you don't necessarily need content projection and the parent to provide input control/template, consider creating your reusable component as a standalone entity that handles all operations independently. This approach can simplify things a bit. Check out this link for an alternative example.

The previous examples provided also address the update problem you encountered.

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

Searching for a way to access the HTTP request header using ReactJS?

Can anyone assist me in retrieving the request header's cookie? I have searched extensively but haven't found a satisfactory document. Please share with me a reliable solution. ...

Iterate through an array of strings within a paragraph tag

In my current situation, I am dealing with an array of strings and would like to iterate through it within a <p> tag if the array is empty. This is what I have so far: <p *ngIf="detailMessageMultilines">{{detailMessageMultilines}}< ...

Unable to retrieve query parameters from the ActivatedRoute class

I currently have a route set up in the routing module like this: { path: 'warning/:type', component: WarningPageComponent } When the application needs to navigate to the warning page, it makes this call: const navigationExtras: NavigationExtras ...

Creating synchronous behavior using promises in Javascript

Currently, I am working with Ionic2/Typescript and facing an issue regarding synchronization of two Promises. I need both Promises to complete before proceeding further in a synchronous manner. To achieve this, I have placed the calls to these functions in ...

Configuring environment variables during Jest execution

A variable is defined in my `main.ts` file like this: const mockMode = process.env.MOCK_MODE; When I create a test and set the variable to true, it doesn't reflect as `'true'` in the main file, but as `'false'` instead. describe ...

Utilize/Absolve/Add a Prefix to angular material scss styles

Issue I am facing a challenge with integrating angular material SCSS into my application. I want to ensure that these styles are isolated and scoped specifically for my application, as it will be embedded within a larger monolith. The goal is to prevent a ...

Encountering a 400 error when attempting to make a

After recently starting to use angular5, I encountered an error when attempting to insert a new row of data into a table. The error message was Failed to load resource: the server responded with a status of 400 (Bad Request) I've experimented with bo ...

Angular router for displaying multiple view groups

What is the most effective strategy for handling two groups of views in Angular? Let me explain how I typically structure my layout in app.component.html: <app-header></app-header> <router-outlet></router-outlet> <app-footer> ...

Using Angular, a function can be called recursively directly from within the HTML

I'm struggling with loading an image because the method getUserProfileImage() is getting triggered multiple times within a loop. Is there a way to ensure the method is only called once during each iteration? I understand that this issue is related to ...

The labels for my Angular Material form within the dialogue are not visible and the styling appears incorrect until I begin inputting information

Upon opening the dialogue, I noticed that only the phone number, email, name, and location fields were properly styled, while the others were not and the labels weren't displaying. Prior to adding appearence="outline", the fields had no sty ...

Is a package.json file missing dependencies?

Curious about the meaning of peerDependencies, I examined the contents of this package.json file. It relates to a library project that is distributed elsewhere. { "name": "...", "version": "...", "description": "...", "author": "...", ...

This code snippet, document.location.search.replace('?redirect=', '').replace('%2F', ''), is failing to execute properly in Firefox

The functionality of document location search replace redirect to another page works in Chrome, however, document.location.search.replace('?redirect=', '').replace('%2F', ''); it does not work in Firefox; instead, ...

Retrieving template variable within a directive's host listener function

Can 'habitCellInfo' be accessed from the template within the onvalueChanged host listener? <div *dxTemplate="let habitCellInfo of 'habitEditCellTemplate'"> <dx-select-box (onValueChanged)=" onHabitEdi ...

Angular refreshes outdated DOM element

Within my Angular (v9) application, I have a simple component. The main goal of this component is to display the current date and time when it is first shown, and then after a 2-second delay, enable a button. Here's the code snippet from app.component ...

Can you explain how to utilize the 'npm' command and its functions?

Understanding npm: As I delve into various projects, they often direct me to utilize npm commands like this one: npm install -g node-windows I decided to explore npm by reading some blog posts and installing Node.js. However, upon attempting to run the a ...

The date in a nodejs application appears to be shifted by one day

Despite similar questions being asked before here, the solutions provided did not resolve my issue. Here is the scenario I am dealing with: https://i.sstatic.net/H9rcO.png Upon clicking save, I collect data from certain fields to generate a date using th ...

Designing a visual showcase with interactive tab links for image selection

I have been working on developing an Angular component that simulates a tab gallery functionality, inspired by this example. Below is my HTML structure: <div class="gallery-container"> <div class="display-container"> ...

Difficulty accessing files with Angular deployment in Nginx through Docker

Recently, I delved into the world of Docker and Nginx in an attempt to deploy my angular application. Unfortunately, I encountered a perplexing issue. Upon executing the command: npm run build, I noticed that my index.html contained script references as f ...

Guide on switching locales from US to Japan in react-big-calendar

Currently, I am trying to customize a calendar component using the react-big-calendar library. My goal is to localize it for Japan, but I'm facing some challenges. Error Message: Unexpected require(). 'ja' is defined but never used. Code S ...

Issue with MUI icon import: React, Typescript, and MUI type error - Overload does not match this call

Within my component, I am importing the following: import LogoutIcon from "@mui/icons-material/Logout"; import useLogout from "@/hooks/auth/useLogout"; const { trigger: logoutTrigger } = useLogout(); However, when utilizing this compo ...