generic3892372
generic3892372

Reputation: 206

How can I intercept the bootstrap "data-target" event?

Elaboration on Question:

I'm using a bootstrap modal dialogue, and I only want it to work if the user is logged in.

While vue.js can make this element disappear entirely if a user is not logged in, or handle links of any kind, 'data-target' is giving me trouble.

Goal: Check if a user is logged in before activating modal. If a user is NOT logged in, I handle it somewhere else in the code (details there are not germane to this question IMO, but involve activating a completely separate modal).

If the user IS logged in, then allow the modal to be activated via 'data-target'

Problem: Currently, when a user is NOT logged in, the 'reportModalIdWithHash' is activated before the 'checkForLogin()'

Code:

          <span
            class="float-right text-muted smaller-font make-clickable"
            data-toggle="modal"
            :data-target="reportModalIdWithHash"
            v-on:click="checkForLogin()"
          >
            Report
          </span>

Note About Preferred Solution:

I'd like to have "checkForLogin()" to happen before the modal is triggered by "data-target".

While I can always make elements dissappear with Vue.js, I want the user to see the option and then when they click on it, if they're not logged in, then present a login instead of the report modal.

Is it possible to intercept and re-fire 'data-target'?

Upvotes: 1

Views: 1518

Answers (1)

tao
tao

Reputation: 90038

Why not use a dynamic data-target?

:data-target="`#${isLoggedIn ? 'fancy' : 'login'}-modal`"

new Vue({
  el: '#app',
  data: () => ({
    isLoggedIn: false
  }),
  methods: {
    handleLogin() {
      // replace this with an async API call...
      this.isLoggedIn = true;
      // and switch modals...
      ['fancy', 'login'].forEach(name => $(`#${name}-modal`).modal('toggle'));
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.js"></script>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" ></script>

<div id="app" class="container">
  <div class="form-check p-3">
    <input class="form-check-input" type="checkbox" v-model="isLoggedIn" id="check">
    <label class="form-check-label" for="check">
      <code>isLoggedIn</code> (click to change)
    </label>
  </div>
  <div class="btn btn-primary"  data-toggle="modal"
       v-text="`Open Report`"
       :data-target="`#${isLoggedIn ? 'fancy' : 'login'}-modal`"></div>
  <div class="modal fade" tabindex="-1" role="dialog" id="login-modal">
    <div class="modal-dialog">
      <div class="modal-content">
        <div class="modal-header">
          <h5 class="modal-title">Login modal</h5>
          <button type="button" class="close" data-dismiss="modal" aria-label="Close">
            <span aria-hidden="true">&times;</span>
          </button>
        </div>
        <div class="modal-body">
          <p>Login modal content goes here.</p>
        </div>
        <div class="modal-footer">
          <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
          <button type="button" class="btn btn-primary" @click="handleLogin" data-dismiss="modal" >Login</button>
        </div>
      </div>
    </div>
  </div>
  <div class="modal fade" tabindex="-1" role="dialog" id="fancy-modal">
    <div class="modal-dialog">
      <div class="modal-content">
        <div class="modal-header">
          <h5 class="modal-title">Fancy report</h5>
          <button type="button" class="close" data-dismiss="modal" aria-label="Close">
            <span aria-hidden="true">&times;</span>
          </button>
        </div>
        <div class="modal-body">
          <p>Fancy report goes here.</p>
        </div>
        <div class="modal-footer">
          <button type="button" class="btn btn-secondary" data-dismiss="modal">Meh...</button>
          <button type="button" class="btn btn-primary">OK</button>
        </div>
      </div>
    </div>
  </div>
</div>


Note: this is a simple proof of concept, not production ready code:

  • don't use Vue + Bootstrap + jQuery as in my example (it's pretty barbaric). You're better off using BootstrapVue (and getting rid of jQuery).
  • You might want to use a single dynamic modal and inject the body, title and footer contents via slots. That's not always better but, in general, leads to DRY-er code at expense of readability.

With BootstrapVue, your button would look more like this:

<b-btn v-b-modal[`${isLoggedIn ? 'fancy' : 'login'}-modal`]> Open Modal</b-btn>

...or, if you want to handle it in a method:

<b-btn @click="handleOpenModal">Open modal</b-btn>

and:

methods: {
  handleOpenModal() {
    this.$bvModal.open(this.isLoggedIn ? 'fancy-modal' : 'login-modal');
  }
}

Upvotes: 3

Related Questions