ng-bootstrap: scrollable doesn't work on modals with component as content

Bug description:

When using a component as the content of a modal rather than a template, with the scrollable option set to true, the modal body doesn’t scroll.

The CSS magic apparently doesn’t work when an additional element (the host element of the component) is inserted between the .modal-content and the .modal-body, but I’m so bad at CSS that I can’t even find a workaround.

Link to minimally-working StackBlitz that reproduces the issue:

https://stackblitz.com/edit/angular-rekfnj?file=app/modal-component.ts

Versions of Angular, ng-bootstrap and Bootstrap:

Angular: 8.1 ng-bootstrap: 5.0.0-rc.1 Bootstrap: 4.3.1

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 2
  • Comments: 16 (9 by maintainers)

Commits related to this issue

Most upvoted comments

Sorry to comment on a closed thread, but I got here via Google and I was dealing with this specific bug, albeit my case was more complicated due to injection of another Component inside the one component my modal opens up. This thread showed me a simple fix, so I’ll leave it here. Thanks everyone above for the help.

Angular: 11.2.5 ng-bootstrap: 9.1.2 Bootstrap: 4.5.0

Host component just needed that [style.overflow]: "auto". The default ngb-modal-window .component-host-scrollable rule comes with overflow: hidden, which is not enough if I’m changing modal-body with new content after I already opened the modal with the host component. So, my final host component becomes:

@Component({
  selector: 'app-modal',
  styleUrls: ['modal.component.scss'],
  host: {
    '[style.overflow]': '"auto"'
  },
  template: `
    <div modal>
      <div class="modal-header">
        <h1 class="modal-title">{{ dto?.title}}</h1>
        <button type="button" class="close" aria-label="Close" (click)="modal.dismiss()">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body">
        <ng-container *ngComponentOutlet="item"></ng-container>
      </div>
      <div class="modal-footer">
        <button ngbAutofocus type="button" class="btn btn-primary" (click)="modal.close()">OK</button>
      </div>
    </div>
	`,
})
export class ModalComponent {
  @ViewChild(ModalDirective) modal;
  public item: Type<any>;
}

-----------------------------------

export class ModalService {
  constructor(private ngbModalService: NgbModal) { }
  (...)
  openModal(content: Type<any>) {
    const modalRef = this.ngbModalService.open(ModalComponent,  { scrollable: true });
    const compRef = modalRef.componentInstance as ModalComponent;
    compRef.item = content;
  }

[UPDATE]: on a side note, I also found out that mine and @jnizet bug must be caused by missing a <div class="modal-content" modal> wrapping up header, body & footer as indicated by https://getbootstrap.com/docs/4.6/components/modal/#scrolling-long-content. After fixing that, no host style was needed.

@benouat thanks for taking the time to reply. According to my package.json I am now running Angular 8.2.14 and @ng-bootstrap/ng-bootstrap 5.3.0 and it wasn’t working. But in an effort to really ensure I wasn’t doing something stupid, I tried something and it now works.

I was wrapping my components html in <form> </form> (so that the submit button in the footer works as expected), and that is what breaks it. The solution was to give the form an id and then in the submit buttin, set that the buttons form attribute to that value. Sorry to have bothered.

@luisVargasGu 100% that did it

@Component({
  selector: '...',
  templateUrl: '...',
  styleUrls: [...],
  host: {
    '[style.display]': '"flex"',
    '[style.flex-direction]': '"column"',
    '[style.overflow]': '"auto"'
  }
}) export class NgbdModalContent {...}

Guys

This is my final word 🤣 tested, and working on Safari, Chrome and Firefox.

I was missing the overflow, of course! So

@Component({
  /* ... */
  host: {
    '[style.display]': '"flex"',
    '[style.flex-direction]': '"column"',
    '[style.overflow]': '"hidden"'
  }
})
export class NgbdModalContent {

I also update the SB → https://stackblitz.com/edit/angular-rekfnj-rydpk1?file=app/modal-component.ts

This works, you just need to change ‘[style.overflow]’: ‘“hidden”’ to ‘[style.overflow]’: ‘“auto”’

Perfect @benouat ! You rock! Thanks a lot.

Thanks @benouat , but I don’t think adding these two styles on the modal content component fixes anything. Unless I miss something in your instructions. Could you provide an example where this workaround works?

Here’s a workaround I found (but it’s a bit fragile, and I suck at CSS):

Replace, in the template of my modal content component

<div class="modal-body ">
  [long content here]
</div>

by

<div class="modal-body px-0">
  <div style="overflow-y: hidden; height: calc(100vh - 15rem);">
    <div class="px-2" style="overflow-y: auto; height: 100%;">
      [long content here]
    </div>
  </div>
</div>