ewomack
ewomack

Reputation: 667

ngx-bootstrap center a submodal over a modal

I have an Angular 8 application using ngx-bootstrap v5.6.1 that opens a modal and then, under certain circumstances, open a second modal on top of the first modal. Both work perfectly, but the second modal is centering to the screen rather than to the modal below it. This is very likely because I'm passing class: 'modal-md modal-dialog-centered' into the second modal, but I haven't been able to find a way to reposition the second modal except for removing the "centered" to have it appear at the top.

I would like to move the second modal up the screen maybe 10% - 20% more. Both modals are their own independent components, because I wanted to make the second modal reusable across the application.

Here is how I am calling the modals

First modal:

this.bsModalRef = this.modalService.show(ModalComponent, { class: 'modal-lg', backdrop: 'static' });

Second modal:

this.bsModalRefConf = this.modalService.show(ConfirmModalComponent, { class: 'modal-md modal-dialog-centered', backdrop: 'static' });

These both use BsModalService from ngx-bootstrap/modal

Thank you!

Upvotes: 2

Views: 2408

Answers (1)

tao
tao

Reputation: 90312

Apply .modal-dialog-centered to the large modal as well and, to move the smaller one up, give its .modal-content a bottom margin. It has to be double the size, because it's centered using flexbox. So to move it up 15vh (15% of device screen height) you need a bottom margin of 30vh.

See it working (in expanded mode):

#exampleModalCenter2 .modal-content {
  margin-bottom: 30vh;
}
.modal-content {
  box-shadow: 0 5px 6px -3px rgba(0,0,0,.2), 0 9px 12px 1px rgba(0,0,0,.14), 0 3px 16px 2px rgba(0,0,0,.12);
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>

<!-- Button trigger modal -->
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModalCenter">
  Launch first modal
</button>

<div class="modal fade" id="exampleModalCenter" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenterTitle" aria-hidden="true">
  <div class="modal-dialog modal-dialog-centered modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="exampleModalLongTitle">Modal title</h5>
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body">
        ...
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
        <button type="button" class="btn btn-primary"  data-toggle="modal" data-target="#exampleModalCenter2">Open second modal</button>
      </div>
    </div>
  </div>
</div>
<div class="modal fade" id="exampleModalCenter2" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenterTitle" aria-hidden="true">
  <div class="modal-dialog modal-dialog-centered modal-md" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="exampleModalLongTitle">Modal title</h5>
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body">
        ...
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
        <button type="button" class="btn btn-primary">Save changes</button>
      </div>
    </div>
  </div>
</div>

Since rendering the backdrop on top of another modal can only done using hacky DOM manipulation, I separated them visually using box-shadow.

A better approach would be to also change the opacity of the larger modal while the smaller one is opened and lower its z-index by 1. You can achieve this using:

  1. javascript: add a class to the large one dynamically based on whether the small one is open or not and change its opacity and z-index when it has that class applied.
  2. css: to do it without js, all you have to do is place the large one after the small one in DOM, as siblings, and use the ~ combinator. Demo:

#exampleModalCenter2 .modal-content {
  margin-bottom: 20vh;
}
.modal-content {
  box-shadow: 0 5px 6px -3px rgba(0,0,0,.2), 0 9px 12px 1px rgba(0,0,0,.14), 0 3px 16px 2px rgba(0,0,0,.12);
}
.modal.show {
  opacity: 1;
  transition: opacity .3s ease-in-out;
}
.modal.show ~ .modal.show,
.modal.show ~ .modal.show * {
  opacity: .5;
  pointer-events: none;
  z-index: 1049;
}
.modal-backdrop.show ~ .modal-backdrop.show {
  opacity: 0;
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>

<!-- Button trigger modal -->
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModalCenter">
  Launch first modal
</button>

<div class="modal fade" id="exampleModalCenter2" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenterTitle" aria-hidden="true">
  <div class="modal-dialog modal-dialog-centered modal-md" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="exampleModalLongTitle">Modal title</h5>
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body">
        ...
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
        <button type="button" class="btn btn-primary">Save changes</button>
      </div>
    </div>
  </div>
</div>
<div class="modal fade" id="exampleModalCenter" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenterTitle" aria-hidden="true">
  <div class="modal-dialog modal-dialog-centered modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="exampleModalLongTitle">Modal title</h5>
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body">
        ...
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
        <button type="button" class="btn btn-primary"  data-toggle="modal" data-target="#exampleModalCenter2">Open second modal</button>
      </div>
    </div>
  </div>
</div>

... at which point moving the small one up becomes less important.

Upvotes: 1

Related Questions