I have this script in my view file, the purpose of it is to populate a section of the same view, but only a small section of it, which is a HTML div with Bootstrap panel classes:
<script type="text/javascript">
function GetVehicles() {
$.get('@Context.Request.Scheme://@hostname/@controller/GetVehicles', {id: @Model.Id}, function (response) {
$("#tabOutVehicles").html(response);
});
}
function GetMedInfo() {
$.get('@Context.Request.Scheme://@hostname/@controller/GetMedInfo', {id: @Model.Id}, function (response) {
$("#tabOutMedInfo").html(response);
});
}
</script>
My complete view, which will display the output generated by the script above:
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}
<script src="~/js/site.js"></script>
<div class="panel panel-primary">
<div class="panel-heading">
<a href="#collapseVehicles" class="btn student-dash-btn" onclick="GetVehicles()" data-toggle="collapse">Vehicles</a>
</div>
<div id="collapseVehicles" class="panel-collapse collapse">
<div id="tabOutVehicles">
</div>
</div>
</div>
<div class="panel panel-primary">
<div class="panel-heading">
<a href="#collapseMedInfo" class="btn student-dash-btn" onclick="GetMedInfo()" data-toggle="collapse"><strong style="color:white">Medical Info</strong></a>
</div>
<div id="collapseMedInfo" class="panel-collapse collapse">
<div id="tabOutMedInfo">
</div>
</div>
</div>
<script type="text/javascript">
function GetVehicles() {
$.get('@Context.Request.Scheme://@hostname/@controller/GetVehicles', {id: @Model.Id}, function (response) {
$("#tabOutVehicles").html(response);
});
}
function GetMedInfo() {
$.get('@Context.Request.Scheme://@hostname/@controller/GetMedInfo', {id: @Model.Id}, function (response) {
$("#tabOutMedInfo").html(response);
});
}
</script>
By clicking on the hyperlinks inside the Bootstrap panel divs, the jQuery method hits my controller action, returns the response, and then puts the response in the applicable div (#tabOutMedInfo / #tabOutVehicles). Both these actions return partial views. Here is what my partial view looks like, both look the same except for the model properties that differ:
@model MyViewModel
<div class="panel-body">
<a data-url="@Url.Action("EditMedInfo", "Controller", new { id = Model.Id })" data-toggle="ajax-modal" data-target="#EditMedInfo" class="btn btn-default">Edit</a>
<div class="form-horizontal">
<div class="">
<div class="form-group">
<div class="col-md-5 col-sm-5 col-xs-5"><label asp-for="Variable" class="control-label"></label></div>
<div class="col-md-7 col-sm-7 col-xs-7">
@Html.DisplayFor(item => item.Variable)
</div>
</div>
</div>
</div>
</div>
When the above hyperlink is clicked, it is supposed to execute JavaScript code that loads a modal for editing, which is not happening, instead it does not open the modal. The JavaScript code is located in my site.js file, which is being imported in my main view.
What I've tried:
I moved the script import tag to both my partial views and then removed it from my view, it then causes the JavaScript code to run and display my modal, but this solution only worked for a while.
New problem:
Then a new problem started occurring, if the first partial view is loaded, and you were to load the second partial view without closing the web page, it causes site.js to be loaded twice into the view, once by the first partial view, and a second time by the second partial view. With site.js loaded twice, it somehow causes my post action to be hit twice, resulting in data being inserted twice for one post action.
I then decided to move site.js to my _Layout.cshtml (ideally how it should be) and tried again, this way around caused the partial views to render like normal, but once again, the modals didn't show when clicking on the hyperlinks found in the partial views.
My theory:
The way I understand it, when the jQuery get methods loads the partial views, it prevents the partial view from seeing site.js, even though it was loaded in by my _Layout.cshtml.
What I preferrably don't want to change:
I don't want to get rid of my small get actions, I built it like this to keep my users as much as possible on one page, and calling the get actions seperately reduces their data usage.
Am I loading site.js correctly? Why doesn't my partial views see site.js?
Edit:
This is my _Layout.cshtml
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>@ViewBag.Title</title>
<environment names="Development">
@*Other scripts omitted *@
<script src="~/js/site.js" asp-append-version="true" defer></script>
</environment>
<environment names="Staging,Production">
@*Other scripts omitted *@
<script src="~/js/site.js" asp-append-version="true" defer></script>
</environment>
</head>
<body>
<div id="modal-placeholder"></div>
@RenderBody()
@RenderSection("scripts", required: false)
</body>
</html>
And here is the JavaScript code located inside site.js:
$(function () {
var placeholderElement = $('#modal-placeholder');
var redirectUrl = "";
$('a[data-toggle="ajax-modal"]').click(function (event) {
var url = $(this).data('url');
redirectUrl = window.location.href;
$.get(url).done(function (data) {
placeholderElement.html(data);
placeholderElement.find('.modal').modal('show');
});
});
placeholderElement.on('click', '[data-save="modal"]', function (event) {
event.preventDefault();
var form = $(this).parents('.modal').find('form');
var actionUrl = form.attr('action');
var dataToSend = form.serialize();
$.post(actionUrl, dataToSend).done(function (data) {
var newBody = $('.modal-body', data);
placeholderElement.find('.modal-body').replaceWith(newBody);
var isValid = newBody.find('[name="IsValid"]').val() == 'True';
if (isValid) {
placeholderElement.find('.modal').modal('hide');
window.location.assign(redirectUrl);
}
}
});
});
});
The JavaScript was written like above to handle server side validation on modals, see the brilliant article here: https://softdevpractice.com/blog/asp-net-core-mvc-ajax-modals/