Using Multiple Bootstrap Modals in ColdBox


In a ColdBox application we may have a listing page where we want to add an edit link which should open in a new popup window when clicked to show that record’s details. We can achieve this using Bootstrap modal. Here’s what we will need to do:

  • Create a new layout
  • Create the listing view
  • Create the edit view
  • Use setView to specify the new layout
  • Test the Bootstrap modal

Create the new layout

Let’s create a new layout for displaying contents with a Bootstrap modal. In this layout we only need the body content. So let’s strip out the header, navigations and footer. Under <app-name>\layouts, create a new file called Modal.cfm, and in this file add the following contents and save it:


<cfoutput>
   <div>#renderView()#</div>
</cfoutput>

Create the listing view

Now let’s create the listing view, e.g. <app-name>\invoices\views\list.cfm. Here’s the important fragment from list.cfm:


<thead>
  <tr align="left">
     <th>Date</th>
     <th>Amount</th>
     <th>Note</th>
     <th width="125" class="center">Actions</th>
  </tr>
</thead>
<tbody>
  <cfloop from="1" to="#arrayLen(rc.invoices)#" index="i">
    <tr>
      <td>#DateFormat(rc.invoices[i].getInvoiceDate(),"dd/mm/yy")#</td>
      <td>#DollarFormat(rc.invoices[i].getInvoiceAmt())#</td>
      <td>#rc.invoices[i].getInvoiceNote()#</td>
      <td width="150" class="center">
        <a href="#event.buildLink('')#">Edit</a>
      </td>
    </tr>
  </cfloop>
</tbody>

To turn the Edit link into a Bootstrap modal popup, change it to this:


<a href="#event.buildLink('your-edit-handler-with-params ')#"  title="Edit Invoice"
  data-toggle="modal" data-target="#invoiceRemoteModal" class="edit action">
  <span class="glyphicon glyphicon-edit" aria-hidden="true"></span>
</a>

The important parts above are:

  • data-toggle=”modal”
  • data-target=”#invoiceRemoteModal”

And also towards the bottom of list.cfm, add the following:


<!-- Modal -->
<!-- launches edit view in a Bootstrap modal -->
<div class="modal fade" id="invoiceRemoteModal" tabindex="-1" role="dialog" aria-labelledby="editInvoiceLabel" aria-hidden="true">
  <div class="modal-dialog">
    <div class="modal-content"></div>
  </div>
</div>

Please note that the id must match the data-target specified earlier in the Edit link. In this case the id of invoiceRemoteModal matches the data-target of invoiceRemoteModal.

Create the edit view

Now let’s create the edit view page (e.g. views\invoices\edit.cfm) (i.e. the content that the Bootstrap remote modal will load when you click the Edit link):


<cfoutput>
  <div class="modal-content">
    <div class="modal-header bg-primary">
      <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
      <h4 class="modal-title" id="editInvoiceLabel">Edit Invoice</h4>
    </div>
    <div class="modal-body">
       <!--- the edit view contents goes here --->
    </div> <!--- modal-body --->
    <div class="modal-footer">
    </div>
  </div><!--- modal content --->
</cfoutput>

Here’s the content for the modal-body:


<form id="frmInvoiceEdit" class="form-horizontal" method="post" action="#event.buildLink('invoices.save')#">
  <div class="form-group required">
    <label for="invoiceType" class="col-md-4 control-label">Invoice Type &nbsp;</label>
    <div class="col-md-3">
      <select name="invoiceType" class="form-control">
        <option value=""></option>
        <option value="Client" <cfif rc.invoice.getInvoiceType() eq "Client">selected</cfif>>Client</option>
        <option value="Supplier" <cfif rc.invoice.getInvoiceType() eq "Supplier">selected</cfif>>Supplier</option>
      </select>
    </div>
  </div>
  <div class="form-group required">
    <label for="invoiceDate" class="col-md-4 control-label">Invoice Date &nbsp;</label>
    <div class="col-md-5 date">
      <div class="input-group input-append date" id="dpEditInvoiceDate">
        <input type="text" class="form-control" name="invoiceDate"  value="#dateFormat(rc.invoice.getInvoiceDate(), 'dd/mm/yyyy')#" placeholder="dd/mm/yyyy"/>
        <span class="input-group-addon add-on"><span class="glyphicon glyphicon-calendar"></span></span>
      </div>
    </div>
  </div>
  <div class="form-group required">
    <label for="invoiceAmt" class="col-md-4 control-label">Invoice Amount ($)&nbsp;</label>
    <div class="col-md-7">
      <input type="text" name="invoiceAmt" class="form-control" value="#rc.invoice.getInvoiceAmt()#" size="35%">
    </div>
  </div>
  <div class="form-group required">
    <label for="invoiceNote" class="col-md-4 control-label">Invoice Note &nbsp;</label>
    <div class="col-md-7">
      <input type="text" name="invoiceNote" class="form-control" maxlength="150" value="#rc.invoice.getInvoiceNote()#" size="45%">
    </div>
  </div>
  <br>
  <div class="form-group">
    <div class="col-md-7 col-md-offset-3">
      <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
      <button type="submit" class="btn btn-primary">Save</button>
    </div>
  </div>
  <div class="form-group">
    <div class="col-md-7">
      <input type="hidden" name="invoice_id" id="invoice_id" value="#rc.invoice.getInvoice_id()#" />
    </div>
  </div>
</form>

Use setView to specify the new layout

In the edit method (action) for invoices handler, ensure you specifically set the Modal layout using the event.setView method, otherwise the default layout will be used, e.g.


public void function edit(event){
  var rc = event.getCollection();
  event.getValue("invoice_id","");
  rc.invoice = invoiceService.get( rc.invoice_id );
  event.setView(name="invoices/edit", layout="Modal");
}

Test the Bootstrap Modal

Ok, if everything was done correctly, you should see something similar to this:

date-multi-modal-1b

When you click on the Edit action (first icon) for the first invoice, it brings up the details for that invoice. However when you click to edit the second invoice, it shows the details of the first invoice. It looks like the data are not cleared after the modal closes. So to fix this issue, we need to clear the data when the modal closes by calling the removeData method. Open up list.cfm and add the following towards the end of the file:


<script>
  $(document).ready(function() {
    $('#invoiceRemoteModal').on('hidden.bs.modal', function(e) {
      $(this).removeData();
    });
  });//document
</script>

Now you should see the correct information when you click the Edit action on each individual invoice to bring up their details in a Bootstrap modal:

date-multi-modal-4a

date-multi-modal-5a

You tested it by clicking on the various form input, and discover that the datepicker no longer works after the initial click. So what is need is to close and re-initialise the datepicker when the modal closes and opens. Edit list.cfm and add the following code fragment replacing the existing fragment. That is, it should now look like this:


<script>
  $(document).ready(function() {
    $('#invoiceRemoteModal').on('hidden.bs.modal', function(e) {
      $(this).removeData();
      $("#dpEditInvoiceDate").datepicker( "destroy" );
    });
    $('#invoiceRemoteModal').on('shown.bs.modal', function (e) {
      $("#dpEditInvoiceDate").datepicker({});
    })
  });//document
</script>

And now the datepicker for the Invoice Date input field should launch every time you click it.

date-multi-modal-3

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s