I am still very new to MVC, JavaScript, and jQuery so please bear with me.
I have a webgrid that contains different terms and their translations. The list of terms is dependent on the 'VMID' chosen from the drop down list above the grid. (Or at least it would be, if it were working correctly.)
The left-most column has an edit link for each term that leads to a Boostrap modal, which is populated with all the values assigned to the ID chosen in that drop down list. I need the terms in the grid to also depend on the value chosen from that list.
The approach I am currently trying goes like this (only pasting the bits relevant to the question) -
Main view (strongly typed with model reference, not included):
<div class="container-fluid">
<div style=" margin-bottom: 1.4%;">
<table>
<tr>
<td style="font-size: medium; margin-bottom: 5px">
@Model.lblVMID:
</td>
<td>
@Html.DropDownListFor(model => model.VMID, new System.Web.Mvc.SelectList(Model.locations, "Key", "Value"), new { @class = "form-control", id = "ddlVMID", onchange = "RepopGrid()" })
</td>
</tr>
</table>
</div>
<div class="table-scrollable well" id="termGrid">
@{Html.RenderPartial("_TermGrid", Model);}
</div>
</div>
<script type="text/javascript">
function RepopGrid() {
VMID = $("#ddlVMID").val();
ShowLoadingDialog();
$.ajax({
url: URLPrefix() + "/Terminology/RepopGrid/" + VMID,
type: "POST",
success: function () {
HideLoadingDialog();
},
error: function (jqXHR, textStatus, errorThrown) {
HideLoadingDialog();
ShowAlert(false, 'Failed to change location\r\n' + errorThrown);
}
})
}
</script>
Partial view (strongly typed with model reference, not included. Same model that the main view uses):
@Model.grid.GetHtml(columns: Model.columns, alternatingRowStyle: "info", nextText: "Next",
previousText: "Previous", tableStyle: "table")
Controller:
public ActionResult Index()
{
TerminologyModel model = new TerminologyModel(clsUtils.PreferredVMID());
return View(model);
}
[HttpPost]
public ActionResult RepopGrid(int VMID)
{
TerminologyModel model = new TerminologyModel(VMID);
return PartialView("_TermGrid", model);
}
The model accepts an 'int VMID' and uses that to retrieve the list of terms from the database, then a foreach runs through each term and assigns them to the grid. This works fine, so I didn't feel a need to post it here (it's a bit long, because there are some special columns that need extra work to get set up).
We have a route configuration file that maps URLS to their corresponding actions in the controllers, in this case:
routes.MapRoute(
name: "TerminologyRepopGrid",
url: "Terminology/{action}/{VMID}",
defaults: new { controller = "Terminology", action = "RepopGrid", VMID = UrlParameter.Optional }
);
I'm not familiar with Ajax, so I'm probably using it completely wrong.
This approach is based on a few places where I've read to put the grid in a partial view, so that's what I've done here.
After I choose a new option, I can see that a whole new grid is being returned in Chrome's element inspector, but that grid is not being applied on top of the existing one.
Again, I have been searching and trying and reading and experimenting and I just can't figure out why mine won't work.
I moved the drop down list to the partial view where the grid is, wrapped everything in an Ajax Form, removed the "RepopGrid" JavaScript and controller actions, and added a parameter to the Index action for a VMID. If the VMID is null or empty (when the page is first loaded or refreshed), it uses the default VMID to generate the model. If a valid VMID is received, then it uses that number to generate the model instead.
Here is the new code for those who might be looking for a similar solution (like last time, only the relevant parts):
Index.cshtml -
<div class="table-scrollable well" id="termGrid">
@Html.Partial("_TermGrid", Model)
</div>
<div class="modal fade" id="editTerm" tabindex="-1" role="dialog" aria-labelledby="editTerm-label" aria-hidden="true">
<div class="modal-dialog" style="width: 290px">
<div class="modal-content" style="width: 290px">
<div class="modal-header" style="border-bottom: none; padding-bottom: 0px;">
<h4 id="lblParamName" align="center"></h4>
</div>
<div class="modal-body" id="editTermBody" style="padding: 8px">
</div>
</div>
</div>
</div>
Partial View -
@{
var ajaxOptions = new AjaxOptions()
{
OnSuccess = "OnSuccess",
OnFailure = "OnFailure",
OnBegin = "OnBegin",
HttpMethod = "Post"
};
using (Ajax.BeginForm("Index", "Terminology", ajaxOptions))
{
<div class="container-fluid" id="termGrid">
<div style=" margin-bottom: 1.4%;">
<table>
<tr>
<td style="font-size: medium; margin-bottom: 5px">
@Model.lblVMID<label>: </label>
</td>
<td>
@Html.DropDownListFor(model => model.VMID, new System.Web.Mvc.SelectList(Model.locations, "Key", "Value"), new { @class = "form-control", id = "ddlVMID", onchange = "this.form.submit()" })
</td>
</tr>
</table>
</div>
</div>
}
}
@Model.grid.GetHtml(columns: Model.columns, alternatingRowStyle: "info", nextText: "Next",
previousText: "Previous", tableStyle: "table")
<script type="text/javascript">
function OnSuccess(data, textStatus, jqXHR) {
HideLoadingDialog();
}
function OnFailure(data, textStatus, jqXHR) {
HideLoadingDialog();
ShowAlert(false, "Oops! Something went wrong. :(");
}
function OnBegin() {
ShowLoadingDialog();
VMID = $("#ddlVMID").val()
ShowLoadingDialog();
$.ajax({
url: URLPrefix() + "/Terminology/Index/" + VMID,
type: "POST",
success: function () {
HideLoadingDialog();
},
error: function (jqXHR, textStatus, errorThrown) {
HideLoadingDialog();
ShowAlert(false, 'Failed to change location\r\n' + errorThrown);
}
})
}
</script>
Controller -
public ActionResult Index(string VMID)
{
if (string.IsNullOrEmpty(VMID))
{
TerminologyModel model = new TerminologyModel(clsUtils.PreferredVMID());
return View(model);
}
else
{
TerminologyModel model = new TerminologyModel(int.Parse(VMID));
return View(model);
}
}
The model's code has not changed since the question was originally asked.