0

The problem is offcanvas3 opens behind offcanvas2.

Like that

$("#open-offcanvas2").on("click", function(){
  $("#offcanvas2").offcanvas("show")
})

$("#open-offcanvas1").on("click", function(){
  $("#offcanvas1").offcanvas("show")
})

$("#open-offcanvas3").on("click", function(){
  $("#offcanvas3").offcanvas("show")
})
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"></script>

<button class="btn btn-primary" type="button" id="open-offcanvas1">Open Offcanvas 1</button>

<div class="offcanvas offcanvas-start" data-bs-scroll="true" tabindex="-1" id="offcanvas1">
  <div class="offcanvas-header">
    <h5 class="offcanvas-title" id="offcanvasWithBothOptionsLabel">Offcanvas 1</h5>
    <button type="button" class="btn-close" data-bs-dismiss="offcanvas" aria-label="Close"></button>
  </div>
  <div class="offcanvas-body">
    <button class="btn btn-primary" type="button" id="open-offcanvas2">Open Offcanvas 2</button>
  </div>
</div>

<div class="offcanvas offcanvas-start" data-bs-scroll="true" tabindex="-1" id="offcanvas3">
  <div class="offcanvas-header">
    <h5 class="offcanvas-title">Offcanvas 3</h5>
    <button type="button" class="btn-close" data-bs-dismiss="offcanvas"></button>
  </div>
  <div class="offcanvas-body">
  </div>
</div>

<div class="offcanvas offcanvas-start" data-bs-scroll="true" tabindex="-1" id="offcanvas2">
  <div class="offcanvas-header">
    <h5 class="offcanvas-title">Offcanvas 2</h5>
    <button type="button" class="btn-close" data-bs-dismiss="offcanvas"></button>
  </div>
  <div class="offcanvas-body">
      <button class="btn btn-primary" type="button" id="open-offcanvas3">Open Offcanvas 3</button>
  </div>
</div>

I tried swapping offcanvas1 and offcanvas2 html codes. And it resolved my issue.

But also it's don't working when there are many offcanvases. Also i don't know if it's a good solution.

How can i resolve it?

Thanks in advance!

Yahya Altintop
  • 204
  • 2
  • 12

1 Answers1

0

I would remove the id's from the buttons.

Changes:

  • Remove the ID's from the open buttons
  • Created two new open buttons to illustrate
  • Close any open when a button is clicked Key change to the code for the questions ask
  • Added a jQuery selector for the target to each button data-target-canvas="#offcanvas2" for example. This can be any valid jQuery selector
  • Updated code to work by class I added to the buttons offcanvas-open instead of an ID - so as illustrated multiple buttons for one thing all work.
  • This all can probably be even simpler with some minor updates to the elements but did not wish too stray too far from the original markup.

EDIT: Added a target to the X button (close) to point to the "prior"

// now just use the data attribute no matter what its target is
$("[data-target-canvas]").on("click", function() {
  $('.offcanvas.offcanvas-start').offcanvas("hide");
  const targ = $(this).data("target-canvas");
  $(targ).first().offcanvas("show");
});
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"></script>

<button class="btn btn-primary" type="button" data-target-canvas="#offcanvas1">Open Offcanvas 1</button>
<button class="btn btn-primary" type="button" data-target-canvas="#offcanvas2">Open Offcanvas 2</button>
<button class="btn btn-primary" type="button" data-target-canvas="#offcanvas3">Open Offcanvas 3</button>

<div class="offcanvas offcanvas-start" data-bs-scroll="true" tabindex="-1" id="offcanvas1">
  <div class="offcanvas-header">
    <h5 class="offcanvas-title">Offcanvas 1</h5>
    <button type="button" class="btn-close" data-bs-dismiss="offcanvas" aria-label="Close" data-target-canvas="#offcanvas3"></button>
  </div>
  <div class="offcanvas-body">
    <button class="btn btn-primary" type="button" data-target-canvas="#offcanvas3">Open Offcanvas 2</button>
  </div>
</div>

<div class="offcanvas offcanvas-start" data-bs-scroll="true" tabindex="-1" id="offcanvas3">
  <div class="offcanvas-header">
    <h5 class="offcanvas-title">Offcanvas 3</h5>
    <button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-target-canvas="#offcanvas2"></button>
  </div>
  <div class="offcanvas-body">
  </div>
</div>

<div class="offcanvas offcanvas-start" data-bs-scroll="true" tabindex="-1" id="offcanvas2">
  <div class="offcanvas-header">
    <h5 class="offcanvas-title">Offcanvas 2</h5>
    <button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-target-canvas="#offcanvas1"></button>
  </div>
  <div class="offcanvas-body">
    <button class="btn btn-primary" type="button" data-target-canvas="#offcanvas1">Open Offcanvas 3</button>
  </div>
</div>

Second example; forgo ANY class selectors so all we need to do is add the data attribute to any button etc. and it simple "works".

/* left in but commented out for clarity. Then added combined function do do both */
/*
$(".offcanvas-open").on("click", function() {
  // hide any open
  $('.offcanvas.offcanvas-start').offcanvas("hide");
  const targ = $(this).data("target-canvas");
  $(targ).first().offcanvas("show");
});
$(".close-me").on("click", function() {
  $('.offcanvas.offcanvas-start').offcanvas("hide");
  const targ = $(this).data("target-canvas");
  $(targ).first().offcanvas("show");
});
*/

// now replace both those with ONE function:
$(".offcanvas-open").add(".close-me").on("click", function() {
  $('.offcanvas.offcanvas-start').offcanvas("hide");
  const targ = $(this).data("target-canvas");
  $(targ).first().offcanvas("show");
});
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"></script>

<button class="offcanvas-open btn btn-primary" type="button" data-target-canvas="#offcanvas1">Open Offcanvas 1</button>
<button class="offcanvas-open btn btn-primary" type="button" data-target-canvas="#offcanvas2">Open Offcanvas 2</button>
<button class="offcanvas-open btn btn-primary" type="button" data-target-canvas="#offcanvas3">Open Offcanvas 3</button>

<div class="offcanvas offcanvas-start" data-bs-scroll="true" tabindex="-1" id="offcanvas1">
  <div class="offcanvas-header">
    <h5 class="offcanvas-title" id="offcanvasWithBothOptionsLabel">Offcanvas 1</h5>
    <button type="button" class="close-me btn-close" data-bs-dismiss="offcanvas" aria-label="Close" data-target-canvas="#offcanvas3"></button>
  </div>
  <div class="offcanvas-body">
    <button class="offcanvas-open btn btn-primary" type="button" data-target-canvas="#offcanvas3">Open Offcanvas 2</button>
  </div>
</div>

<div class="offcanvas offcanvas-start" data-bs-scroll="true" tabindex="-1" id="offcanvas3">
  <div class="offcanvas-header">
    <h5 class="offcanvas-title">Offcanvas 3</h5>
    <button type="button" class="close-me btn-close" data-bs-dismiss="offcanvas" data-target-canvas="#offcanvas2"></button>
  </div>
  <div class="offcanvas-body">
  </div>
</div>

<div class="offcanvas offcanvas-start" data-bs-scroll="true" tabindex="-1" id="offcanvas2">
  <div class="offcanvas-header">
    <h5 class="offcanvas-title">Offcanvas 2</h5>
    <button type="button" class="close-me btn-close" data-bs-dismiss="offcanvas" data-target-canvas="#offcanvas1"></button>
  </div>
  <div class="offcanvas-body">
    <button class="offcanvas-open btn btn-primary" type="button" data-target-canvas="#offcanvas1">Open Offcanvas 3</button>
  </div>
</div>

THIRD example; target the container class selectors so all we need to do is add the data attribute to any container; then hook it to the button classes and it simply "works".

/* Here we use the button class to determine the "next" target 
 *  If the button is "btn-close" then we go to the target of our "pointed to" element.
 *  If the button is NOT a "btn-close" then we simply use OUR target-canvas element.
 *  Since we need it more than once, we create a string canvasTarget to reuse.
 *  "event.delegateTarget" is what the event is hooked to (things with a data-target-canvas)
 *  "event.target" is whatever is clicked (the buttons) from our list; whatever is ON a "type" of button"; we had these so just used them: ".btn-close, .btn.btn-primary"
 */
$("[data-target-canvas]")
  .on("click", ".btn-close, .btn.btn-primary", function(event) {
    $('.offcanvas.offcanvas-start').offcanvas("hide");
    const canvasTarget = 'target-canvas';
    const base = $(event.delegateTarget).data(canvasTarget);
    const isClose = this.classList.contains('btn-close');
    //go get the value of our targets target
    const altTarg = $(base).data(canvasTarget);
    // when true we use the alt else we used the base from our delegate
    const nextTarg = isClose ? altTarg : base;
    $(nextTarg).first().offcanvas("show");
  });
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"></script>

<span class="just-a-button" data-target-canvas="#offcanvas1">
<button class="btn btn-primary" type="button" >Open Offcanvas 1</button></span>

<div class="offcanvas offcanvas-start" data-bs-scroll="true" tabindex="-1" id="offcanvas1" data-target-canvas="#offcanvas2">
  <div class="offcanvas-header">
    <h5 class="offcanvas-title">Offcanvas 1</h5>
    <button type="button" class="btn-close" data-bs-dismiss="offcanvas" aria-label="Close"></button>
  </div>
  <div class="offcanvas-body">
    <button class="btn btn-primary" type="button">Open Offcanvas 2</button>
  </div>
</div>

<div class="offcanvas offcanvas-start" data-bs-scroll="true" tabindex="-1" id="offcanvas3" data-target-canvas="#offcanvas1">
  <div class="offcanvas-header">
    <h5 class="offcanvas-title">Offcanvas 3</h5>
    <button type="button" class="btn-close" data-bs-dismiss="offcanvas"></button>
  </div>
  <div class="offcanvas-body">
  </div>
</div>

<div class="offcanvas offcanvas-start" data-bs-scroll="true" tabindex="-1" id="offcanvas2" data-target-canvas="#offcanvas3">
  <div class="offcanvas-header">
    <h5 class="offcanvas-title">Offcanvas 2</h5>
    <button type="button" class="btn-close" data-bs-dismiss="offcanvas"></button>
  </div>
  <div class="offcanvas-body">
    <button class="btn btn-primary" type="button">Open Offcanvas 3</button>
  </div>
</div>
Mark Schultheiss
  • 32,614
  • 12
  • 69
  • 100
  • First of all thanks for your reply. But I must open `offcanvas1` when `offcanvas2` is closed. – Yahya Altintop Mar 21 '23 at 17:42
  • I updated to also add a target to the X button on each; pretty much the same logic but kept it separated for clarity - could be combined in 1 function; THEN did the combined for both. – Mark Schultheiss Mar 21 '23 at 17:59
  • I added a second example where I removed all the classes I added and simply used the `data-target-canvas=` – Mark Schultheiss Mar 21 '23 at 18:12
  • I added yet a third example with a re-use of the targets for each element - so they all act independent of whatever our target says is "prior" for that. A bit more complicated but more flexible. You could for example have a Prev/Next button within each instead of a "named" button - Prev is like a "close" and Next is like the current button inside each. – Mark Schultheiss Mar 21 '23 at 19:13