Partial View replaces Parent view - asp.net-mvc

I'm working on web app developed in ASP.Net MVC, having a partial view which should be rendered inside its parent view.
Parent view has a HTML Dropdown, on-change event should bind respective data to partial view. But on selection change, the complete parent view is replaced with partial view (child view).
Parent View (Index.cshtml)
<h3>Please Select Group</h3>
#using (Html.BeginForm("EmployeeDeptHistory", "Home", FormMethod.Post))
{
#Html.AntiForgeryToken()
if (ViewBag.DepartmentList != null)
{
#Html.DropDownList("DepartmentName", ViewBag.DepartmentList as SelectList, "-- Select --", new { Class = "form-control", onchange = "this.form.submit();" })
}
}
<div>
#{Html.RenderPartial("_EmployeeDeptHistory");}
</div>
Partial View (_EmployeeDeptHistory.cshtml)
#model IEnumerable<PartialViewApplSol.Models.EmployeeDepartmentHistory>
#if (Model != null)
{
<h3>Employees Department History : #Model.Count()</h3>
foreach (var item in Model)
{
<div style="border:solid 1px #808080; margin-bottom:2%;">
<div class="row">
<div class="col-md-2">
<strong>Name</strong>
</div>
<div class="col-md-5">
<span>#item.Name</span>
</div>
</div>
<div class="row">
<div class="col-md-2">
<strong>Shift</strong>
</div>
<div class="col-md-5">
<span>#item.Shift</span>
</div>
</div>
<div class="row">
<div class="col-md-2">
<strong>Department</strong>
</div>
<div class="col-md-5">
<span>#item.Department</span>
</div>
</div>
<div class="row">
<div class="col-md-2">
<strong>Group Name</strong>
</div>
<div class="col-md-5">
<span>#item.GroupName</span>
</div>
</div>
<div class="row">
<div class="col-md-2">
<strong>Start Date</strong>
</div>
<div class="col-md-5">
<span>#item.StartDate</span>
</div>
</div>
<div class="row">
<div class="col-md-2">
<strong>End Date</strong>
</div>
<div class="col-md-5">
<span>#item.EndDate</span>
</div>
</div>
</div>
}
}
I think the possible mistake is returning partial-view on drop down selection changed.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult EmployeeDeptHistory(FormCollection form)
{
IEnumerable<EmployeeDepartmentHistory> empHistList;
using (IDbConnection con = new SqlConnection(connectionString))
{
empHistList = con.Query<EmployeeDepartmentHistory>("sp_StoredProc", new { DeptId = form["DepartmentName"] }, commandType: CommandType.StoredProcedure);
}
return View("_EmployeeDeptHistory", empHistList);
}

Instead of standard form submit, you need to use jQuery.ajax() function to load partial view inside HTML element without replacing parent view. Here are those steps:
1) Remove onchange event from DropDownList helper, and assign AJAX callback bound to change event:
View
#Html.DropDownList("DepartmentName", ViewBag.DepartmentList as SelectList, "-- Select --", new { #class = "form-control" })
jQuery (inside$(document).ready())
$('#DepartmentName').change(function () {
var selectedValue = $(this).val();
if (selectedValue && selectedValue != '')
{
$.ajax({
type: 'POST',
url: '#Url.Action("EmployeeDeptHistory", "ControllerName")',
data: { departmentName: selectedValue };
success: function (result) {
$('#targetElement').html(result); // assign rendered output to target element's ID
}
});
}
});
2) Remove FormCollection and use a string argument which has same name as AJAX callback argument, also make sure the action method returns PartialView:
Controller
[HttpPost]
public ActionResult EmployeeDeptHistory(string departmentName)
{
IEnumerable<EmployeeDepartmentHistory> empHistList;
using (IDbConnection con = new SqlConnection(connectionString))
{
empHistList = con.Query<EmployeeDepartmentHistory>("sp_StoredProc", new { DeptId = departmentName }, commandType: CommandType.StoredProcedure);
}
return PartialView("_EmployeeDeptHistory", empHistList);
}
3) Finally, don't forget to add ID for target element specified by AJAX callback's success part to load partial view:
View
<div id="targetElement">
#Html.Partial("_EmployeeDeptHistory")
</div>

Related

How to print data of join query which are stored in Viewbag in ASP.NET MVC with Entity Framework?

I want to display data from 2 different tables which are stored in ViewBag at view side but I'm unable to print the data, I get an error
'object' does not contain a definition for 'Name'
The code at controller side
public ActionResult Packages()
{
int Prov_id = 1;
using (var db = new DataContex())
{
ViewBag.pack = db.Packages.Where(x => x.ProviderId == Prov_id).ToList();
ViewBag.service = db.GroupServices.Join(db.PackageServices,
gs => gs.ServiceId,
ps => ps.ServiceId,
(gs, ps) => new
{
name = gs.ServiceName
})
.ToList();
return View();
}
View markup:
#foreach (var item in ViewBag.pack)
{
<div class="col-md-6 bg-white mt-3">
<div class="card border package-grid p-3">
<div class="row">
<div class="col-md-8">
<input type="hidden" />
<h4 class="font-weight-bold py-2">#item.PackageName</h4>
#foreach (var item1 in ViewBag.service)
{
<h6 class="py-1">#item1.Name</h6>
}
<p class="py-3">#item.PackageDescription</p>
</div>
</div>
<div class="row">
<div class="col-md-12 mt-3 d-flex justify-content-between flex-wrap">
<p><strike> Rs. #item.PackagePrice</strike> <span>Rs. #item.PackageOfferPrice</span> </p>
<span>Remove</span>
</div>
</div>
</div>
</div>
}
That is because when you created ViewBag.service you have created anonymous object with property as name with n as LowerCase and at view side you are trying to use #item.Name as N as UpperCase.
Correct the property name and it will work.

Cannot apply indexing with [] to an expression of type 'HttpRequest'

I am trying to get a value from a textbox of my View.
This is my View:
#model MyDataIndexViewModel
#{
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-12">
<h1>Meine Daten</h1>
</div>
</div>
var item = Model.User;
<div class="row">
<div class="col-xs-6 col-sm-6 col-md-6 myDataTitle">Email</div>
<div class="col-xs-6 col-sm-6 col-md-6">
#Html.TextBox("txtEmail", "", new { placeholder = item.Email})
</div>
</div>
}
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-12">
<a class="btn btn-default pull-right" href="/ChangeMyData/Save">Speichern</a>
</div>
</div>
This is my Controller:
[HttpPost]
public ActionResult Save()
{
var email = Request["txtEmail"].ToString();
return View();
}
I get the error just as it says in the Title.
Thank you in advance!
VIEW:
#model MyDataIndexViewModel
#using (Html.BeginForm("Save", "CONTROLLER_NAME"))
{
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-12">
<h1>Meine Daten</h1>
</div>
</div>
var item = Model.User;
<div class="row">
<div class="col-xs-6 col-sm-6 col-md-6 myDataTitle">Email</div>
<div class="col-xs-6 col-sm-6 col-md-6">
#Html.TextBox("txtEmail", "", new { placeholder = item.Email, id="txtEmail"})
</div>
</div>
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-12">
<a class="submit btn btn-default pull-right">Speichern</a>
</div>
</div>
}
CONTROLLER
[HttpPost]
public ActionResult Save()
{
var email = Request.Form["txtEmail"].ToString();
return View();
}
You can either use strongly-typed viewmodel binding:
View
#model MyDataIndexViewModel
#* other stuff *#
#Html.TextBox("txtEmail", Model.Email)
Controller
[HttpPost]
public ActionResult Save(MyDataIndexViewModel model)
{
var email = model.Email;
return View();
}
Or use a TextBoxFor directly for model binding:
#model MyDataIndexViewModel
#* other stuff *#
#Html.TextBoxFor(model => model.Email)
Or if you still want to use HttpRequest members, Request.Form collection (a NameValueCollection) is available to retrieve text from txtEmail input:
[HttpPost]
public ActionResult Save()
{
var email = Request.Form["txtEmail"].ToString();
return View();
}
Note that Request["txtEmail"] is discouraged due to no compile time safety applied for it, because the key value may retrieved from Request.QueryString, Request.Form or other HttpRequestBase members.
Similar issue:
MVC TextBox with name specified not binding model on post
Access form data into controller using Request in ASP.NET MVC

bootstrap modal to appear when dropdownlist item is selected in mvc

I want a bootstrap modal with partial view to popup when a user selects the dropdownlist item.
For each selected item the popup should refresh with new content when the user selects a different item in the dropdownlist. From the code below, I could able to make the ajax and then redirect to partial view with model values but unable to display the modal popup
Index.cshtml
<div class="form-group">
#Html.LabelFor(model => model.SelectedIssue, htmlAttributes: new { #class = "control-label col-md-3" })
<div class="col-md-9">
#Html.DropDownListFor(model => model.SelectedIssue, Model.IssueDetails, "Please Select", new { #class = "form-control", #id = "IssueId" })
#Html.ValidationMessageFor(model => model.SelectedIssue, "", new { #class = "text-danger" })
</div>
</div>
$("#IssueId").change(function () {
$.ajax({
type: 'GET',
url: '#Url.Action("GetActionDetails")',
dataType: 'html',
data: { id: $("#IssueId").val() },
success: function (data) {
$('#modal-content').html(data);
$('#modal-container').modal('show');
},
error: function (ex) {
alert('Failed to retrieve action details' + ex);
}
});
return false;
});
The dropdown selection is making an ajax call and calling the below method in the controller
public ActionResult GetActionDetails(string id)
{
ActionDetails model = new ActionDetails();
model.ActionTaken = "Action Taken ";
model.AdviceGiven = "Advice Given to";
return PartialView("ActionDetails", model);
}
This is then redirecting to PartialView ActionDetails view which is below.
#model OnCallLogging.Models.ActionDetails
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button>
<h3 class="modal-title">Action Details</h3>
</div>
<div class="modal-body">
<div class="form-horizontal">
<div class="form-group">
#Html.LabelFor(m => Model.ActionTaken, new { #class = "control-label col-sm-3"})
<div class="col-sm-9">
#Html.DisplayFor(m => m.ActionTaken, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => Model.AdviceGiven, new { #class = "control-label col-sm-3" })
<div class="col-sm-9">
#Html.DisplayFor(m => m.AdviceGiven, new { #class = "form-control" })
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-warning" data-dismiss="modal">Close</button>
</div>
And in the Layout.cshtml, the following markup is written before the body closing tag.
<div id="modal-container" class="modal fade hidden-print" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
</div>
</div>
</div>
and in the script.css
.modal-content {
width: 600px !important;
margin: 30px auto !important;
}
When I run the code, the screen goes dim but no popup appears. When I debug I could see ajax calling the controller action and redirecting to partial view, but the popup does not appear.
Not sure what am I missing to show the popup with model properties. Could anyone please help.
Since you are seeing the controller action being called while debugging, the harder part is working. The most likely explanation for your issue is in your javascript "success:":
//change from this:
$('#modal-content').html(data);
//to this:
$('.modal-content').html(data);
You can optionally, change your <div class="modal-content"> to <div id="modal-content">

PagedListPager page always null

This used to work... but now the >> anchor tag of the PagedListPager always passes null to the controller for the page value required...
VS 2013 Web Express & MVC 4 with latest package updates for all.
Just like in Scot Allen's MVC 4 intro, I have a partial view with a PagedListPager
The Controller:
public ActionResult Catalog(string Id= "0", int page=1)
{
var CurrentItemsPage = (get-data-blaw-blaw-blaw).ToPagedList(page,18);
var model = new ShowRoomCatalogPackage(){ CurrentItems = CurrentItemsPage};
return View(model);
}
The catalog page
#model craftstore.Models.ShowRoomCatalogPackage
#{
ViewBag.Title = "Catalog";
Layout = "~/Views/Shared/_Details.cshtml";
}
#using (Ajax.BeginForm("Catalog", "Home", new { category = #Model.SelectedCategoryId, page = 1 },
new AjaxOptions
{
UpdateTargetId = "products",
InsertionMode = InsertionMode.Replace,
HttpMethod = "post"
}
)
)
{
<div class="container" >
<div class="row">
<div class="col-lg-10 col-md-5 col-sm-4 dropdown-menu">
#Html.LabelFor(m => m.SelectedCategoryId)
#Html.DropDownList("id", Model.CategoryItems, new { #id = "ddlCategories", onchange = "this.form.submit();" })
</div>
<div class="col-lg-2 col-md-2 col-sm-1">
#Html.ActionLink("Your Cart", "Index", "ShoppingCart", "", new { #class = "btn btn-green btn-lg" })
</div>
</div>
<div class="row">
#Html.Partial("_CatalogPartial", Model.CurrentItems)
</div><!-- row -->
</div><!-- container -->
}
<br />
<br />
#section Scripts
{
<script type="text/javascript">
new AnimOnScroll(document.getElementById('grid'), {
minDuration: 0.4,
maxDuration: 0.7,
viewportFactor: 0.2
});
</script>
}
The partial view:
#model IPagedList<ShowroomCatalog>
<div id="productList">
<div class="col-lg-12 col-md-12 col-sm-12">
<div class="pagedList" data-cs-target="#productList">
#Html.PagedListPager(Model, page => Url.Action("Index", new { category = ViewBag.SelectedCategoryId, page }), PagedListRenderOptions.MinimalWithItemCountText)
</div>
<ul class="grid effect-2" id="grid">
#foreach(var item in Model)
{
var path = String.Format("~/Content/Images/catalog/{0}/{1}", item.OfferType, item.ImagePath);
<li>
<div class="itembox">
<div class="imagebox">
<a href="#Url.Action("Detail", "Home", new { id = item.Id })" title="Detail for #item.CatalogName">
<img class="catalogimg" src="#Url.Content(path)" />
</a>
</div>
<p>#item.CatalogName</p>
</div>
</li>
}
</ul>
</div>
</div><!-- productlist -->
Now the rendered partialview in the browser doesn't have anything in the anchors which may or may not be normal...
<div class="pagedList" data-cs-target="#productList">
<div class="pagination-container"><ul class="pagination"><li class="disabled PagedList-skipToPrevious"><a rel="prev">«</a></li><li class="disabled PagedList-pageCountAndLocation"><a>Showing items 1 through 18 of 65.</a></li><li class="PagedList-skipToNext">»</li></ul></div>
</div>
And when you hover on the >> it doesn't show the page parameter in the URL:
Again, back in the Controller - I get the category (15) but no page parameter or Request.URL parameter is passed to the controller - it's not hiding because of some routing mistake...I think...
How do I get the paging control to work again...???
[EDIT: one more note - the url path on the pager is /controller/action/category/page rather than what shows up on Scot Allen's OdeToFood example where it's equivalent would be /controller/action/category?page=n (like /Home/Catalog/15?page=1 ]
I was missing the JS for the PagedList class anchor element.
var getPage = function () {
var $a = $(this);
var options = {
url: $a.attr("href"),
data: $("form").serialize(),
type: "get"
};
$.ajax(options).done(function (data) {
var target = $a.parents("div.pagedList").attr("data-otf-target");
$(target).replaceWith(data);
});
return false;
};
And this is fired off by :
$(".main-content").on("click", ".pagedList a", getPage);
BUT, this means you need to have your #RenderBody() call in your _Layout.cshtml file wrapped in something with a class of main-content. An example:
<section class="content-wrapper main-content clear-fix">
#RenderBody()
</section>

Model properties null on Ajax post from list box change event

I have a view which contains a list box. when users click on an item in the list box I have to post to a controller action method to see the value of the items selected/de-selected in the list box.
So it is posting to the controller action but the model is posted as null. When I post to the controller, I do serialize the form.
In other pages of my application when I serialize the form and post to the controller, the model is never null. I am not sure whats going on in this page but here is the code.
JS File
var serviceEntryURL = '#Url.Action("ServiceSystemSelection", "ServiceEntry")';
$('#systemlstbox').change(function () {
// alert('x');
var overlay = $('<div>loading errorcodes and parts..</div>').prependTo('body').attr('id', 'overlay');
$.post(serviceEntryURL,
$("#form").serialize(),
function (data) {
// $("#runDatestreeview").remove();
// $("#testExceptiontreeview").remove();
// $("#treeview").remove();
// $("#main").html(data);
// $("#ErrorCodeDisplay").empty();
}, "html");
overlay.remove();
});
View
#model RunLog.Domain.Entities.ServiceEntry
#{
ViewBag.Title = "Create";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#using (Html.BeginForm(new { id = "form", enctype = "multipart/form-data" }))
{
<fieldset>
<legend>Enter a new Service Log Entry</legend>
<h3>
</h3>
#Html.ValidationSummary(true)
<div class="exception">#(ViewBag.ErrorMessage)</div>
<div class="bodyContent">
<span class="leftContent">
#Html.Label("Service Request Number")
</span><span class="rightContent">[Generated] </span>
</div>
<div class="bodyContent">
<span class="leftContent">
#Html.Label("Service Request Date / Time")
</span><span class="rightContent">
#Html.EditorFor(model => model.ServiceDateTime)
</span>
</div>
<div class="bodyContent">
<span class="leftContent">
#Html.Label("Technician")
</span><span class="rightContent">
#Html.DropDownList("TechnicianID", String.Empty)
</span>
</div>
<div class="bodyContent">
<span class="leftContent">
#Html.Label("System")
</span><span class="rightContent">
#Html.ListBoxFor(model => model.SelectedSystemIDs, new
MultiSelectList(ViewBag.SystemID, "Text", "Value",
Model.SelectedSystemIDs), new { id = "systemlstbox", name = "listbox" })
</span>
</div>
}
Controller Action
[HttpPost]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult ServiceSystemSelection(ServiceEntry serviceEntry)
{
}
I fixed it, the form serialization line was wrong.
$('#systemlstbox').change(function () {
// alert('x');
$.post(serviceEntryURL,
$('form').serialize(),
function (data) {
}, "html");
});

Resources