Having trouble setting a default value within an Angular component using ControlValueAccessor?

Demo: https://plnkr.co/edit/cMu3lI3PkxHRErJE3T93?p=preview

I've encountered an issue with setting default values for ngModel or formControlName when using ControlValueAccessor in multiple components.

For instance, in the provided demo, there is a select element that offers better user experience and visuals. However, in the ngOnInit lifecycle hook, setting the model to be the first option in the select's choices when the select has a required attribute set to true seems to be problematic.

When the select has required set to true, it should always have a value. Currently, the default value is only set after clicking on an option.

One workaround could be to always set the value in the parent component, but this approach would result in unnecessary code duplication, which is not desired. The ability to set a default value should not be a difficult task.

Below is a snippet of the code we are dealing with:

  private _model: any;

  set model(val) {
    this._model = val;
  }

  get model() {
    return this._model;
  }

  propagateChange = (_: any) => {};

  registerOnChange(fn: () => any) {
    this.propagateChange = fn;
  }

  registerOnTouched() {}

  writeValue(value: any) {

    if (value !== undefined) {
      this.model = value;
      this.cd.markForCheck();
    }
  }

  ngOnInit() {

    if (!this.model && this.required) {
      this.model = this.options[0];
    }
    else if (!this.required) {
      this.model = null;
    }

    this.propagateChange(this.model);
  }

Upon reviewing the demo, it is evident that setting the model in ngOnInit is not functioning as expected.

What could be causing this issue?

Answer №1

At the time when

this.propagateChange(this.model);
is called, the function has not been registered yet.

I have come up with two possible solutions:

1) Update the model after the propagateChange function has been assigned:

export const NOOP: any = () => {};
...

propagateChange = NOOP;

registerOnChange(fn: () => any) {
  this.propagateChange = fn;
  if(this.required) {
    fn(this.model);
  }
}

writeValue(value: any) {
  if (value !== undefined && this.propagateChange !== NOOP) {
    this.model = value;
    this.cd.markForCheck();
  }
}

View the Plunker Example

2) Utilize the ngModelChange event:

@Output() ngModelChange = new EventEmitter();

this.ngModelChange.emit(this.model);

View the Plunker Example

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

Angular is a variable that offers constant service

In my Angular application, I have a service that retrieves an array called array_item from an api call. In the component, I have two variables named var_1 and var_2, both set to the same value obtained from the service. For example: var_1 = this.service.a ...

Angularfire/Firebase utilizes the Authorization Code Grant flow for OAuth

I am trying to understand the authentication flow used by applications that depend on Firebase for single sign-on authentication. While I know that most SPA and client applications use the "implicit flow" due to everything happening in the browser without ...

Experimenting with viewProvider in a component test

@Component({ selector: 'app-entity-details', templateUrl: './entity-details.component.html', styleUrls: ['./entity-details.component.scss'], viewProviders: [{ provide: ControlContainer, useFactory: (container: ...

Tips for customizing the appearance of ng-bootstrap accordion

Looking to enhance the appearance of ng-bootstrap accordion with some unique fade styling. Any suggestions on how to accomplish this? ...

Learn how to create a versatile TypeScript function that combines an array parameter and values to form an object

I've created a function that combines an array of keys with an array of values to form an object. Here's how the function looks: function mergeToObject(keys: string[], values: string[]) { const object:? = {} for (let i = 0; i < keys.length ...

Resetting and marking an Angular2 form as untouched

Is it possible to reset a form and mark it as untouched, clean, etc after submission while staying on the page to avoid resubmission? this.myForm.reset() this.myForm.markAsPristine() this.myForm.controls['options_name'].markAsUntouch ...

Issue verifying the initial certificate in Nodeshift

Currently, I am in the process of deploying an Angular application using nodeshift, but I have encountered the error message "unable to verify the first certificate" whenever I execute the following command: nodeshift --strictSSL=false --dockerImage=buch ...

Having trouble activating the ENTER key press event listener for the QuillJS editor in Angular 4 and above

I have been trying to set up an event listener for the ENTER key press in QuillJS using addBinding as described in the official documentation here. However, despite successfully configuring listeners for other keys like BACKSPACE, I am unable to get the EN ...

The element is inferred to have the 'any' type. No index signature matching the parameter type 'string' was found on the 'User1' type

I have been experimenting with computed properties in TypeScript, but I've encountered a specific issue: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'User1'. ...

Exploring the capabilities of extending angular components through multiple inheritance

Two base classes are defined as follows: export class EmployeeSearch(){ constructor( public employeeService: EmployeeService, public mobileFormatPipe: MobileFormatPipe ) searchEmployeeById(); searchEmployeeByName(); } ...

The utility of commander.js demonstrated in a straightforward example: utilizing a single file argument

Many developers rely on the commander npm package for command-line parsing. I am considering using it as well due to its advanced functionality, such as commands, help, and option flags. For my initial program version, I only require commander to parse ar ...

Troubleshooting a problematic dependency in Angular with the ngx-favicon package

Could someone please clarify why I am encountering issues when trying to run npm install ngx-favicon? npm install ngx-favicon npm ERR! code ERESOLVE npm ERR! ERESOLVE unable to resolve dependency tree npm ERR! npm ERR! While resolving: <a href="/cdn-cgi ...

Using the attribute selector in an Angular 2 standalone component

In my research, I have come across several sources mentioning that an angular component selector can be enclosed in square brackets similar to a directive selector. However, when I tried it, it did not work for me: import { ChangeDetectionStrategy, Compone ...

I'm encountering an issue with my Angular 8 function not running, and I'm unsure of the reason behind it as there are no error messages appearing

Here is a function that I have: Join(movementId: string, movement: Movement, userId: string) { let fetchedUserId: string; let userList = []; fetchedUserId = userId; userList = movement.userList; userList.push(fetchedUserId); movement.userList ...

Experience a new way to log in with signInWithPopup, leaving the Email

I am currently working on developing a registration form that utilizes Firebase auth for authentication. There are two methods available for registering users: Using Email / Password Provider Using Google Auth Provider Here is the process I follow: Ste ...

What is the process for recording soft-navigation modifications in mPulse Boomerang for an Angular application?

I have been trying to use the BOOMR.plugins.Angular plugin for AngularJS 1.x, but I have not been able to find an example or plugin that works with Angular. After reviewing the documentation, I have come up with the following solution: @Injectable() export ...

Error message: Unable to associate with DIRECTIVE as it is not a recognized attribute of 'div'

Despite searching through similar questions about this error, I have not been able to find a solution. The issue arises with my highlight directive, which takes an input parameter index. Initially, the directive worked perfectly when declared within the m ...

How can I properly customize and expand upon a Material UI ListItem component?

I'm currently working with TypeScript version 3.4.5 and Material UI version 4.2. I have the following code snippet: interface MyItemProps { name: string; value: string; } function Item({ name, value, ...props }: ListItemProps<'li&apo ...

Angular2 - navigating through routes with different language preferences

Hello, I am interested in setting up routes with language included in the format below: www.domain.com/lang/sometimes For example: www.domain.com/en/sometimes www.domain.com/de/sometimes Is it feasible to create a route like this: RouterModule.forChil ...

What is the best way to forward specific props from a parent to its children?

Currently, I am working on a React + Typescript architecture called "forward." The purpose of this architecture is to pass all props received down to its children components. However, I have encountered an issue where I want to restrict the type of props ...