AndyM
AndyM

Reputation: 1200

Component inside ng-bootstrap modal

I have a scenario where I'm using a form displayed inside a modal popup which is created using ng-bootstrap. Within the modal I'm using a custom component to display validation messages for each form field but it doesn't look like that component is being picked up and executed by the Angular lifecycle.

I open the popup from it's parent component using a button:

<button type="button" (click)="openFormModal()">Add something</button>

Which executes the following code where MyModalComponent has been imported:

openFormModal() {
  const modalRef = this.modalService.open(MyModalComponent);
}

The modal itself is fairly unremarkable apart from the custom validation-messages component. The code sample has various things omitted for brevity:

<div class="modal-body">
  <form [formGroup]="myForm" class="form">
    <input type="text" [ngClass]="'form-control'" formControlName="name" required maxlength="100">
    <validation-messages [control]="myForm.controls.names" controlName="Name"></validation-messages>
  </form>
</div>

The validation-messages component is as follows:

import { Component, Input } from '@angular/core';
import { FormControl } from '@angular/forms';
import { ValidationService } from './notifications.validation.service';

@Component({
  selector: 'validation-messages',
  template: `<div *ngIf="errorMessage !== null" class="invalid-notification">{{errorMessage}}</div>`
})
export class ValidationMessages {
  @Input() control: FormControl;
  @Input() controlName: string;

  constructor() { }

  get errorMessage() {
    for (let propertyName in this.control.errors) {
      if (this.control.errors.hasOwnProperty(propertyName) && (this.control.touched && this.control.invalid)) {
        return ValidationService.getValidatorErrorMessage(propertyName, this.controlName, this.control.errors[propertyName]);
      }
    }
    return null;
  }
}

validation-messages works perfectly in a standard form i.e. not in a modal but when the HTML for the modal renders on the screen the validation-messages renders as follows:

<validation-messages controlname="Name"></validation-messages>

Instead of how it renders normally:

<validation-messages controlname="Business name" ng-reflect-control="[object Object]" ng-reflect-control-name="Business name">
  <!--bindings={
    "ng-reflect-ng-if": "false"
  }-->
</validation-messages>

I'm pretty new to Angular and I'm sure that it's something pretty fundamental that I'm missing.

It's probably also worth mentioning that I had to add schemas: [CUSTOM_ELEMENTS_SCHEMA], to my app.module.ts to get the modal to not complain about the validation-messages component being present in the HTML.

Any help would be greatly appreciated.

Edit

validation-messages is also part of a notifications module:

import { NgModule } from "@angular/core";
import { ValidationMessages } from "./notifications.validationmessages";
import { CommonModule } from '@angular/common';

@NgModule({
    imports: [CommonModule],
    declarations: [ValidationMessages],
    exports: [ValidationMessages]
  })
export class NotificationsModule {}

Upvotes: 0

Views: 1978

Answers (1)

Ian A
Ian A

Reputation: 6163

The error message regarding adding CUSTOM_ELEMENTS_SCHEMA gave a clue that Angular did not know about the ValidationMessages component. As your ValidationMessages component is part of the NotificationsModule you need to ensure that this module finds it way up into the global application module (often app.module.ts).

Modifying app.module.ts as follows should fix the issue:

@NgModule({
    imports: [
        ...,
        NotificationsModule
    ],
    declarations: [
        ...
    ],
    bootstrap: [
        ...
    ]
})
export class AppModule {
}

Regarding the comment "Does adding that make the component available at the root level?" - it will only be available at the root level if you add it to the exports of the NotificationsModule - like this:

import { NgModule } from "@angular/core";
import { ValidationMessages } from "./notifications.validationmessages";
import { CommonModule } from '@angular/common';

@NgModule({
    imports: [CommonModule],
    declarations: [ValidationMessages],
    exports: [ValidationMessages] // Available at root level/other modules
  })
export class NotificationsModule {}

Upvotes: 1

Related Questions