How to programmatically inject content in bootstrap-vue modal body and footer?

ace picture ace · Aug 24, 2018 · Viewed 13.2k times · Source

I want to implement this functionality in vuejs app using bootstrap vue modal component:

When the user clicks on the Delete button on the page UI :

  • It shows the modal with a dynamic content in its body: "Are you sure you want to delete customer: customer_name_here"

  • If the user clicks on the 'Cancel' button: The modal goes away.

  • If the user clicks on the 'OK' button:

  • It changes the modal body content to: 'Deleting customer 'customer_name_here' ... , it disables the Cancel and OK buttons and it calls the API to delete the customer.

When successful response is received from the API:

  • It changes the modal body content to: 'Successfully deleted customer 'customer_name_here'
  • Display only the OK button in the modal footer, which if clicked modal goes away.

This the code so far:

 <b-button   v-b-modal.modal1  variant="danger">Delete</b-button>

    <b-modal id="modal1" title="Delete Customer" 
@ok="deleteCustomer" centered no-close-on-backdrop -close-on-esc ref="modal">
        <p class="my-4">Are you sure, you want to delete customer:</p>
        <p>{{customer.name}}</p>
      </b-modal>

Vue JS code:

deleteCustomer(evt) {

      evt.preventDefault()
      this.$refs.modal.hide()

      CustomerApi.deleteCustomer(this.customer.id).then(response => {
          // successful response
        })

Answer

Sphinx picture Sphinx · Aug 27, 2018

If I understand correctly, you'd like to display the Modal content based on different state combinations.

As your descriptions, there should be 2 state:

  1. deletingState: it indicates whether begin deleting

  2. loadingState: it indicates whether is waiting the response from the server

Check Bootstrap Vue Modal Guide, then search keyword= Disabling built-in buttons, you will see we can use cancel-disabled and ok-disabled props to control the disable state of default Cancel and OK buttons (or you can use the slot=modal-footer, or modal-ok, modal-cancel.).

Other props you may use: ok-only, cancel-only, busy.

Finally bind v-if and props with the state combinations to show the content.

Like below demo:

Vue.config.productionTip = false
new Vue({
  el: '#app',
  data() {
    return {
      customer: {name: 'demo'},
      deletingState: false, // init=false, if pop up modal, change it to true
      loadingState: false // when waiting for server respond, it will be true, otherwise, false
    }
  },
  methods: {
    deleteCustomer: function() {
    	this.deletingState = false
      this.loadingState = false
      this.$refs.myModalRef.show()
    },
    proceedReq: function (bvEvt) {
    	if(!this.deletingState) {
        bvEvt.preventDefault() //if deletingState is false, doesn't close the modal
        this.deletingState = true
        this.loadingState = true
        setTimeout(()=>{
          console.log('simulate to wait for server respond...')
          this.loadingState = false
          this.deletingState = true
        }, 1500)
      } else {
      	console.log('confirm to delete...')
      }
    },
    cancelReq: function () {
    	console.log('cancelled')
    }
  }
})
.customer-name {
  background-color:green;
  font-weight:bold;
}
<!-- Add this to <head> -->
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap/dist/css/bootstrap.min.css" />
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.css" />

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<!-- Add this after vue.js -->
<script src="//unpkg.com/babel-polyfill@latest/dist/polyfill.min.js"></script>
<script src="//unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.js"></script>

<div id="app">
  <b-button v-b-modal.modal1 variant="danger" @click="deleteCustomer()">Delete</b-button>

  <b-modal title="Delete Customer" centered no-close-on-backdrop no-close-on-esc ref="myModalRef"
  @ok="proceedReq($event)" @cancel="cancelReq()" :cancel-disabled="deletingState" :ok-disabled="loadingState" :ok-only="deletingState && !loadingState">
    <div v-if="!deletingState">
      <p class="my-4">Are you sure, you want to delete customer:<span class="customer-name">{{customer.name}}</span></p>
    </div>
    <div v-else>
      <p v-if="loadingState">
        Deleting customer <span class="customer-name">{{customer.name}}</span>
      </p>
      <p v-else>
        Successfully deleted customer <span class="customer-name">{{customer.name}}</span>
      </p>
    </div>
    
  </b-modal>
</div>