Introduction
There are no standards of how to use bootstrap dialogs in ASP.NET MVC.
Often, many questions appear on a phase of implementation:
- How to create dialogs?
- Where dialogs should be placed in HTML?
- How to fill dialogs with dynamic information?
- How to subscribe to dialog events?
This tip gives an approach to organize and use bootstrap dialogs effectively.
Utility Function
Let’s create a utility function which will be used to create Bootstrap Dialogs.
DialogUtils = {
ShowDialog: function(dialogOptions) {
var container = $("[data-dialog-container=\"" + dialogOptions.url + "\"]");
if (container.length) {
return;
}
var newContainer = $("<div></div>");
newContainer.attr("data-dialog-container", dialogOptions.url);
$("body").append(newContainer);
container = newContainer;
$.post(dialogOptions.url, dialogOptions.data, function(response, status, xhr) {
if (status == "error") {
console.error("Couldn't load dialog " + dialogOptions.url +
" due to error: " + xhr.statusText);
return;
}
container.html(response);
var dialog = $('.modal', container);
dialog.modal('show');
dialog.on('hidden.bs.modal', function() {
if (dialog.data("dialog-result") != undefined) {
var dialogResultHandler = "on" + dialog.data("dialog-result");
if (dialogOptions[dialogResultHandler] !== undefined) {
dialogOptions[dialogResultHandler](dialog);
}
}
container.remove();
});
});
}
};
And the usage is:
DialogUtils.ShowDialog({
url: "@Url.Action("SubmitPaymentConfirmation")",
data: $("#SubmitPayment").serialize(),
onConfirm: function () {
$("#SubmitPayment").submit();
},
onConfirmAndPrint: function () {
$("#Print").val("true"); $("#SubmitPayment").submit();
}
});
This function takes as a parameter dialogOptions
which contains the following properties:
url
: address of action which provides dialog HTML
data
: parameter of action
onConfirm
, onConfirmAndPrint
– callbacks which are invoked when dialog is closed with specific state (for example: Confirm
, ConfirmAndPrint
, etc.)
For callbacks to work dialogs should be closed with specific state. By default, bootstrap doesn’t have any, so the wrapper function for modal.hide
would be required:
$(function () {
var originalModal = $.fn.modal;
$.fn.modal = function(option, result) {
if (option == 'hide' && typeof result == 'string') {
var $this = $(this);
$this.data("dialog-result", result);
arguments[1] = null;
}
originalModal.apply(this, arguments);
};
});
Now the dialog template should contain triggers which close dialog with specific state:
@model Dialogs.Models.SubmitPaymentConfirmation
@{
Layout = null;
}
<div class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close"
data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span></button>
<h4 class="modal-title">Payment Confirmation</h4>
</div>
<div class="modal-body">
<div class="row">
<label class="col-md-6 text-nowrap text-right">Amount:</label>
<span>@Html.DisplayFor(model => model.Amount)</span>
</div>
<div class="row">
<label class="col-md-6 text-nowrap text-right">Name On Card:</label>
<span>@Html.DisplayFor(model => model.NameOnCard)</span>
</div>
<div class="row">
<label class="col-md-6 text-nowrap text-right">CVV:</label>
<span>@Html.DisplayFor(model => model.CreditCardCvv2)</span>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default btn-primary"
onclick="$(this).closest('.modal').modal('hide', 'Confirm')">
<span class="glyphicon glyphicon-ok"></span> CONFIRM
</button>
<button type="button" class="btn btn-default"
onclick="$(this).closest('.modal').modal('hide', 'ConfirmAndPrint')">
<span class="glyphicon glyphicon-ok-circle"></span> CONFIRM AND PRINT
</button>
<button type="button" class="btn btn-default" data-dismiss="modal">
<span class="glyphicon glyphicon-remove-circle"></span> CANCEL
</button>
</div>
</div><!---->
</div><!---->
</div>
<!---->
You can see that Confirm
and ConfirmAndPrint
buttons contain handlers which close the dialog with specific state.
The last thing to say is dialog represents a separate action in the controller:
public ViewResult SubmitPaymentConfirmation(SubmitPaymentConfirmation paymentPageModel)
{
return View("SubmitPaymentConfirmation", paymentPageModel);
}
Explanation
For each dialog, a new container is created and attached to body. Dialog is loaded into container by url provided in the parameter. When dialog is closed, its close state is written to dialog-result
data field and callback with this state is executed. After that, container with dialog is removed. Dialog template is stored in a separate file and may contain scripts/styles assuming they do not correlate with page content.