MVC Partial Views in Bootstrap Modals
bootstrap ASP.NET MVC ASP.NET Core
I couldn’t think of a joke for this one. At least none that I was partial to.
If you want to view all the code for this post it is in this GitHub repository.
The partial views in ASP.NET MVC are quite handy for organizing code. They allow pieces of HTML to be reused, including databinding.
Here is a quick explanation, without going to far down the rabbit hole. Views are razor files, a code/html file that .NET compiles into plan HTML server-side. Normal views link with a layout page and return a full HTML page. Partial views just return a snippet of HTML.
Bootstrap modals and other forms of dialogs work pretty well conceptually with partial views. They are not as tied to the pages they appear on and may end up being used on multiple pages. Modals can also hold content that needs to be loaded on demand. Display details for items in a list, for example, can be one common use of a modal.
Setting up a modal to load a partial view is actually pretty straight forward, there are just a few potential hiccups that can be easily avoided if one knows about them.
First, some requirements. I am assuming an ASP.NET MVC site with a bootstrap NuGet package. If you are using ASP.NET Core then the bootstrap NuGet package is replaced by a bootstrap bower package, but really just be sure you have bootstrap. You will also need to get bootstrap on the page itself, you can get help with that at bootstrap’s site.
If the partial view doesn’t yet exist, then let’s create it. I am going to create a partial view called ModalContent.cshtml
. We can cover what goes in the view a bit later. Then create a method on a controller that returns the partial view. For this simple sample, I just used the HomeController
.
public ActionResult ModalAction(int Id)
{
ViewBag.Id = Id;
return PartialView("ModalContent");
}
With those prerequisites out-of-the-way, add a bootstrap modal to the page.
That is just the default bootstrap modal definition, it just happens to be devoid of content. Note that the Id is modal-container
.
Then we add a link to the partial view and link it to the modal. There is some divergence here between ASP.NET Core and older ASP.NET. The tag helpers in Core really make it easier.
Here is old way.
Here is the new way.
<a asp-action="ModalAction" asp-controller="Home" asp-route-id="1" data-target="#modal-container" data-toggle="modal">Open Modal</a>
Both versions accomplish the same thing. They create an anchor tag that links to the controller action that returns the partial view and they contain a hook to the modal. The data-toggle="modal"
attribute is used by the bootstrap javascript to add a click event to the anchor tag that opens the modal. The data-target
attribute tells the bootstrap JavaScript which modal to open.
It is important to note here that Bootstrap version 3.3 deprecated the auto fetch feature and some additional JavaScript will be needed once it is removed. In earlier versions, however, it handles everything for you. The reason version 3.3 removes the capability was that they determined it was out of scope for what is primarily a CSS framework. You can read more about the issue here.
What we have now should work, however the modal will be blank as we don’t have anything in the partial view. So lets fix that.
It is just the basic modal content, nothing fancy.
We are not quite done yet, there is still the issue of refreshing the content of the modal. As it stands, the partial view is requested once, the first time it is opened. After that the modal just displays the previously fetched html.
A simple but crude way to fix this issue is to reset the modal when it is closed so that bootstrap recreates it next time it is opened.
I want to note that this relies on bootstrap recreating the modal if it can’t find the
bs.modal
data attribute.
If the modal shouldn’t be cleared every time than this bit of JavaScript could be changed to only clear the modal if some criteria was met.
If you are using a version of bootstrap that no longer has the html fetching built in then add the following JavaScript to page. It recreates what bootstrap was doing.
This was taken straight from the bootstrap 4 docs. Also, since this bit of JavaScript is called every time the modal is opened, we won’t need to clear the modal on close.
That should give us what we set out for, a bootstrap modal that displays partial views. There are couple additional features that we could add, for example, using a form or knockout in the modal. I can take a look at those features at a later date.
You could say that this leaves us with just a partial view.
Sorry, sorry, I will let myself out.
.
.
.
.
.
.
Wait, this is my blog.
Comments
With the <a asp-action=”DownloadBatch” asp-controller=”Sensor” asp-route-id=”1” data-target=”#mymodal” data-toggle=”modal”>Open Modal</a> does not work and @Html.ActionLink(“Download Sensor Readings”, “DownloadBatch”, “Sensor”, new { @* Tells the bootstrap javascript to do its thing@ data_toggle = “modal”, @ Needed to link to the html of the modal*@ data_target = “#myModal” }) only partially works, can you please assist me
Which version of things are you using? It has been awhile since I looked at this and a lot has changed since I wrote this.
Also, I am not sure what you mean by partially works, so it is hard to offer much help. I would recommend writing this up as a reproduceable example and asking the question at stackoverflow. You can drop a link to the question back here if you want.
What i mean by partially working, it’s loading the PartialView but not the modal
In that case, I would try and get a simple bootstrap modal working first, without the partial view loading. See https://getbootstrap.com/javascript/#live-demo in the bootstrap documentation for an example. Than you can look for help on just the boostrap part.
I just realized that I left the script tags needed out of the blog post, which is my bad. Take a look at https://github.com/AlexanderLindsay/BootstrapModalPartialView/blob/master/BootstrapModalPartialView/Views/Shared/_Layout.cshtml where I use the bundled scripts and https://github.com/AlexanderLindsay/BootstrapModalPartialView/blob/master/BootstrapModalPartialView/App_Start/BundleConfig.cs where the bundled scripts are defined.
Sidenote: it looks like I need to fix the order comments are displayed and maybe the time component of comment time.
Great blog post! Thank you for this :)
Hi, where do I put this scripts, I mean, I want to know in which files do I out this codes. Thanks in advance!
@Favricyo You can see the full project in this repo: https://github.com/AlexanderLindsay/BootstrapModalPartialView There is a .net core version and a one with out .net core. I haven’t touched either of them in a while so the core one in particular is probably out of date.
However, almost all the code in this example goes in the index.cshtml file in Views/Home. https://github.com/AlexanderLindsay/BootstrapModalPartialView/blob/master/BootstrapModalPartialView/Views/Home/Index.cshtml
Does that help?
If you need more background you can start from this tutorial: https://docs.microsoft.com/en-us/aspnet/mvc/overview/getting-started/introduction/adding-a-view
Then once you have created the view, you can add the code in this blog post to it. However, that might require some adjustments to any changes to MVC that have occurred since I first wrote this.
Okay, is because i’m experience a lot of bugs, but any way, thank you.
Here is my struggle: http://stackoverflow.com/questions/44011435/modal-turns-into-a-dark-screen-when-opened-a-second-time
Hi, Alex, just to note that your markup should be “data-target=#modal-container”
Good catch @Stefan. I fixed it now.
I also updated the github repo where the full examples are, including updated the .net core version to use .NetCoreApp 1.1
Hi, this is a great tutorial. However, I have some problem to apply that on my web app. At the first time when I click on the ActionLink, it will call the QuickView action in the Product controller and show the information of the product. However, when I click on the ActionLink for another product, it won’t call the QuickView action. Also, the content of the modal window still displays the information of the previous product. Basically, the problem is that the action method only gets called in the first time that I click on the ActionLink. It won’t get called anymore in any subsequence click of the ActionLink. When I right click the page and inspect the element, I can see that the modal action link is generated correctly. I’m so confused about it. Please help.
Main view:
ProductSummary:
QuickView (the modal content):
Action method:
@IY
It sounds to me like my method of deleting the existing modal data (
$(this).removeData('bs.modal');
) might not be working for you, this post is possible pretty out of date. How to fix it probably depends on what version of bootstrap you are using.The bootstrap 3.3 docs has a bit that goes into how to accomplish a similar thing that you might want to reference. The only issue being that you will need to fetch the html page yourself. The second half of this post goes into this a bit, see the last embedded gist.
I think that is a good place to start looking for the error.
Hi Alex, thanks for this great Tutorial. I just have a problem at the very beginning. If I click on the ActionLink, nothing happens. The focus is not reaching the action. If I delete the data-toggle-parameter from the ActionLink, the Action is reached and the partial view is shown.
I tried several different things without success. Seems that data-toggle=”modal” is blocked somehow.
The examples from bootstrap-page work, but this is not the way I’d like it…
My Actionlink:
@Html.ActionLink(“kopieren”, “CopyDialog”, “Projects”, new { Id = Model.Id }, new { @class = “btn btn-secondary”, data_toggle = “modal”, data_target = “#picker” })
…couldn’t see a fault. Is there a script missing?
BundleConfig included:
bundles.Add(new ScriptBundle(“~/bundles/jquery”).Include( “~/Scripts/jquery-{version}.js”));
bundles.Add(new ScriptBundle(“~/bundles/jqueryval”).Include( “~/Scripts/jquery.validate*”));
bundles.Add(new ScriptBundle(“~/bundles/jqueryajax”).Include( “~/Scripts/jquery.unobtrusive-ajax.js”));
And _Layout included at top: @Styles.Render(“~/Content/css”) @Scripts.Render(“~/bundles/modernizr”)
And at the bottom: @Scripts.Render(“~/bundles/jquery”) @Scripts.Render(“~/bundles/jqueryajax”) @Scripts.Render(“~/bundles/bootstrap”) @RenderSection(“scripts”, required: false)
I’m totally out of ideas :(
…I think my Problem is Bootstrap 4. Sorry but I could not get over it. Could someone help with some code (and explanation) for MVC?
Leave a comment