Injectable Angular Reactive Form

I've encountered an issue with a utility component I developed called the "error display component." This component is designed to handle errors in a generic way.


export class ShowErrorComponent {
  // path refering to the form-element
  @Input('path') controlPath = '';
  @Input('name') formName = '';

  constructor(private ngForm: NgForm) {}

  get errorMessages(): string[] | null {
    const form = this.ngForm.form;
    const control = form.get(this.controlPath);
    if (!control || !control.touched || !control.errors) {
      return null;
    }
    return this.getDisplayMessages(control.errors);
  }
  ....
}

I'm using the ShowErrorComponent in two forms. One form uses the template-driven approach while the other uses the reactive approach. The error display works as expected in the template-driven form, but when used in the reactive form, I encounter the following error:

ERROR NullInjectorError: R3InjectorError(AppModule)[NgForm -> NgForm -> NgForm]: 
  NullInjectorError: No provider for NgForm!
    at NullInjector.get (core.mjs:6359:27)
    at R3Injector.get (core.mjs:6786:33)
    at R3Injector.get (core.mjs:6786:33)
    at R3Injector.get (core.mjs:6786:33)
    at ChainedInjector.get (core.mjs:13769:36)
    at lookupTokenUsingModuleInjector (core.mjs:3293:39)
    at getOrCreateInjectable (core.mjs:3338:12)
    at Module.ɵɵdirectiveInject (core.mjs:10871:12)
    at NodeInjectorFactory.ShowErrorComponent_Factory [as factory] (show-error.component.ts:9:32)
    at getNodeInjectable (core.mjs:3523:44)

The error-component is being called within the context of the following HTML snippet:

<form
  novalidate
  class="register-form"
  (ngSubmit)="registerMember(registerForm.value)"
  [formGroup]="registerForm"
>
  <div formGroupName="personalInfo">
    <div class="form-group">
      <h3>Personal info:</h3>
      <div class="input-group mb-3">
        <label class="input-group-text" for="gender">Gender</label>
        <select class="form-select" id="membership" formControlName="gender">
          <option value="diverse">Diverse</option>
          <option value="male">Male</option>
          <option value="female">Female</option>
        </select>
      </div>
      <app-show-error name="Gender" path="personalInfo.gender"></app-show-error>
      ...
   </div>
    ...
 </div>
</div>

The registerForm variable refers to my FormGroup and is initialized inside the constructor, rendering correctly when <app-show-error> is commented out.

Here is the relevant code snippet for the component associated with the preceding HTML snippet:

 constructor(fb: FormBuilder) {
    this.registerForm = fb.group({
      personalInfo: fb.group({
        gender: ['diverse'],
        firstname: ['', [Validators.required]],
        lastname: ['', [Validators.required]],
        birthdate: [new Date(), [Validators.required]]
      }),
      ...
    }

I have already added ReactiveFormsModule to my Register module. My question is, why am I encountering this error?

Answer №1

NgForm is only applicable to template-driven forms, which is why you encounter an injection error when using it in the reactive example.

To ensure your error component functions correctly with both form libraries, consider injecting ControlContainer instead and accessing the root formDirective from there. Here's how you can achieve this:

export class DisplayErrorComponent {
  ...

  constructor(private controlCont: ControlContainer) {}

  get errorMessageList(): string[] | null {
    const mainDir = this.controlCont.formDirective as (NgForm|FormGroupDirective)
    const formElem = mainDir.form;
    const contVal = formElem.get(this.contPath);

    ...
  }
  ...
}

Cheers!

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

An async function cannot be used as a Constructor

I am in the process of creating a constructor function using JavaScript. This constructor needs to be asynchronous because I am utilizing the Phantom JS module for data scraping. As a result, an asynchronous function must be used to scrape data through Pha ...

Setting up a Schema in Firebase database using NodeJS

Although I am not an expert in JS/NodeJS, I do have some experience working with express-mongoose. Currently, I am leaning towards the MVC approach, which involves creating schemas and importing them. Since Firebase database is a NoSQL database like mong ...

Leveraging Angular 8's ngIf directive in combination with the async pipe to dynamically display or hide HTML elements

I've been attempting to dynamically show and hide HTML elements based on the result of a service call. I have tried using *ngIf="messageService.getData() | async", but it doesn't seem to be working as expected. With the async, the "Failure Messag ...

Tips for manipulating a shape and adjusting the vertices later in three.js

Greetings and thank you in advance for your assistance! I have been facing challenges when creating shapes with the mouse using THREE.Shape. While I am able to draw and edit shapes that are centered on the canvas without any issues, I encounter problems wh ...

How can I import the googleapis library in Angular?

I'm currently working on integrating the Google Drive API into one of my projects. The Node.js quick start guide requires me to import file-reading and googleapis libraries. However, I've encountered some issues when trying to import them into ap ...

Struggling to send an object through a node route for rendering a page?

Currently tackling a node.js project using express.js. I have a route that renders an ejs page and passes along the team object. Strangely, when I try to access <%= team.member.name %>, it returns as undefined despite the information being present. A ...

The file path for Multer upload folder in the MySQL database is not correctly formatted

Utilizing Multer modules in my Node.js application, I successfully uploaded an image to a designated folder and passed the correct path to my MySQL database. However, I encountered an issue with the file path formatting. The problem lies in the absence of ...

What is the process of retrieving a dynamic array value based on checkbox selection in AngularJS?

I need help with a situation where I am trying to use Angular to get the value of a checkbox. I have a Java object on my HTML page and when a user checks an individual box, that single value should be added to my array. If the user checks 'Select All& ...

Can someone guide me on creating a slideshow using Ionic?

Having trouble integrating a javascript/css slideshow into Ionic. Ionic does not support the use of ".style" in elements. Need assistance, below is the code: <head> <title>Slideshow</title> <style> .slides {display:none;} </styl ...

Mastering the art of modifying click events with jQuery

Currently, I am delving into the world of JavaScript and JQuery, specifically exploring a reference for the click event from jquery.js. In my endeavors, I have attempted to override the click event, but to no avail. Despite my efforts to make the new even ...

Comparing prevProps and this.props in React Native Redux: What is the most effective method?

Does anyone know how to efficiently handle triggering a function in my React Native app only when a specific prop has changed? This is the current implementation I have: componentDidUpdate(prevProps) { if (prevProps.a !== this.props.a) { <trigger ...

Different Approach to Guarantee API

Here is the current structure of the promise executor: let p = new Promise((resolve, reject) => { }); It would be much cleaner if it were like this: let p = new Promise(r => { // r.resolve() / r.reject(); }); Is there a possibility to upd ...

Creating a registration and authentication system using firebase

When using Google authentication with Firebase, is the Signup and Login logic the same? I am creating a page for user authentication but I'm unsure if I should have separate pages for signing up and logging in. This confusion arises from the fact that ...

Angular Ant Design Pagination

Currently, I am working on implementing cards and pagination in Angular version 7 using Ant Design. While following the guidelines on the Ant Design website () for cards, I noticed that it does not provide instructions on how to combine cards with pagina ...

Using multiple Helmet React Typescript within React.createElement is not valid

For the past two days, I've been struggling with a SEO component in React that keeps throwing a React.createElement error. Can anyone provide assistance in resolving this issue? SeoModule.tsx import * as React from 'react'; import ...

The Fetch POST request seems to be acting sporadically, as it is not

In my current project, I am utilizing ReactJS, Express, and PostgreSQL to create an application that features three icons. When a user clicks on one of these icons, a corresponding value is sent to the database. Initially, this functionality worked as expe ...

Working with DOM Element Selections in AngularJS

After spending a day searching for ways to perform DOM selection in AngularJs, I came across the following code snippet: var elem = angular.element(document.querySelector("#myDiv")); elem.removeClass("selected"); I'm still unsure if AngularJs of ...

Jimdo: Generate a spinning sliced circle with the click of a button

I'm attempting to achieve a spinning CD/Disk effect when the play button is clicked. I have a sample code below that represents the player's state during playback. What I envision is an image with a play button on top. Upon clicking the button, ...

What is the best method for extracting a particular value from my dataset?

I'm interested in creating a variable that stores the IsUserSiteOwner value from the data. Can someone help me with this? Any suggestions on how I can achieve this task? ...

Instantiate an model when the AJAX call successfully returns

There is a User model defined as: var UserModel = Backbone.Model.extend({ defaults: { handle: '', email: '', uuid: '', userpic: '', tokenlogin: '' } }); A c ...