I want to display a partial view inside a main view upon clicking view link, within the same page. Help me please, I am newbie in MVC. Is there any other way to do it other than using the Ajax.ActionLink()?
This is my Add Detail controller.
public ActionResult DisplayDetails()
{
SqlConnection connect = new SqlConnection(ConfigurationManager.ConnectionStrings["connect"].ToString());
connect.Open();
DataSet ds = ExecuteQuery("select EmployeeID, EmployeeName, EmailID from EmployeeDetails");
IList<AddDetails> lst = new List<AddDetails>();
AddDetails ad;
foreach (DataRow dr in ds.Tables[0].Rows)
{
ad = new AddDetails();
ad.EmployeeId = Convert.ToInt32(dr["EmployeeID"]);
ad.EmployeeName = dr["EmployeeName"].ToString();
ad.EmailId = dr["EmailID"].ToString();
lst.Add(ad);
}
connect.Close();
return PartialView("DisplayDetails", lst);
}
Here is the main view
AddDetail view(main view).
#model mvcEmployeeTask.Models.AddDetails
<link href="#Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
#using (Html.BeginForm("AddDetail", "AddDetails", FormMethod.Post))
{
<table>
#* <tr>
<td>
#(Html.Label("Employee ID : "))
</td>
<td>
#Html.TextBoxFor(model => model.EmployeeId)
#Html.HiddenFor(model => model.EmployeeId)
</td>
</tr>*#
#Html.HiddenFor(model => model.EmployeeId)
<tr>
<td>
#(Html.Label("Employee Name : "))
</td>
<td>
#(Html.TextBoxFor(model => model.EmployeeName))
</td>
</tr>
<tr>
<td>
#(Html.Label("Email ID : "))
</td>
<td>
#(Html.TextBoxFor(model => model.EmailId))
</td>
</tr>
<tr>
<td>
<input type="submit" value="submit" name="Add" />
</td>
<td>
#* #Html.ActionLink("View", "DisplayDetails")*#
#Html.ActionLink("View", "DisplayDetails")
</td>
</tr>
</table>
#Html.Action("DisplayDetails", "AddDetails");
}
Here is the partial view (Display view).
#model IList<mvcEmployeeTask.Models.AddDetails>
#{
Layout = null;
}
#using (Html.BeginForm("DisplayDetails", "AddDetails", FormMethod.Get))
{
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>DisplayDetails</title>
<link href="#Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
</head>
<body> <div class="table" align="center">
<table border="1" >
<tr>
<th>EmployeeID</th>
<th>EmployeeName</th>
<th>Email</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#item.EmployeeId
</td>
<td>
#item.EmployeeName
</td>
<td>
#item.EmailId
</td>
<td>
#Html.ActionLink("Edit", "EditDetails", new { id= item.EmployeeId })
</td>
<td>
#Html.ActionLink("Delete", "DeleteDetails", new { id= item.EmployeeId })
</td>
</tr>
}
</table>
</div>
</body>
</html>
}
Please Help me!!
You should use
#Ajax.ActionLink
Reason:
Ajax.ActionLink is much like Html.ActionLink counterpart, it also creates the hyperlink Click here but when user clicks it and have the JavaScript enabled browser, Ajax.ActionLink sends the asynchronous request instead of navigating to new URL. With Ajax.ActionLink we specify what controller’s action method to invoke and also specify what to do with the response coming back from the action method and it suits your case really well.
Instead of
#Html.ActionLink("View", "DisplayDetails")
Description:
It will render the partial view on the same index screen instead of opening new window.
Something like this
#Ajax.ActionLink(" ", "ViewDetails", "Auditor", new AjaxOptions { UpdateTargetId = "yourviewDiv"}) //yourviewdiv is id of div where you want to show your partial view onClick
Your Main View
#model mvcEmployeeTask.Models.AddDetails
<div id = "yourviewDiv">
// it will populate your partial view here.
</div>
<link href="#Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
#using (Html.BeginForm("AddDetail", "AddDetails", FormMethod.Post))
{
#Ajax.ActionLink(" ", "ViewDetails", "Auditor", new AjaxOptions { UpdateTargetId = "yourviewDiv"})
}
load following div using its id on particular event(say button click of your main view) then partial view will be load on your main view.
<div id="loadpartialview">
#Html.Partial("_yourPartialViewName")
</div>
here is nice tutorial how to implement it:
http://mvc4beginner.com/Tutorial/MVC-Partial-Views.html
The simple version of code is
<div>
#Html.Partial("PartialView1", Model.partialModel)
</div>
Theory:
To have it dynamic you need to create ajax call to render the action on server and insert the result to the page.
the question how to implement this has been already answered here:
MVC Partial view with controller, ajax - how do I ge the partial controller to get data?
Related
I have this partial view. This works, ie, when the user clicks the button, an ajax trip is made to the server, and it updates the partial view and it comes down and replaces the current div with the updated Div and shows the Promo Message.
However, it seems there should be a better way to do this. In other words, is it necessary to replace the entire partial view? Isn't there a way to send just the data up to the server, and then update just the message when it gets back, like maybe via a JSON call?
Controller:
public ActionResult ApplyPromoCode(OrderViewModel orderViewModel) {
orderViewModel.PromoMessage = "Promo has been applied";
return PartialView("PromoPartial", orderViewModel);
}
Partial View:
#model NTC.PropertySearch.Models.OrderViewModel
#using (Ajax.BeginForm("ApplyPromoCode", "OrderSummary", new AjaxOptions { InsertionMode = InsertionMode.Replace, UpdateTargetId = "promo" }))
{
<div id="promo">
<table>
<td>
#Html.LabelFor(m => m.PromoCode)
</td>
<td>
#Html.TextBoxFor(m => m.PromoCode)
</td>
<td>
#Html.ValidationMessageFor(m => m.PromoCode)
</td>
<td>
<input type="submit" value="Apply Promo Code" />
</td>
<td>
#Html.DisplayFor(m=> m.PromoMessage)
</td>
</table>
</div>
}
you can do this to
Controller
public ActionResult ApplyPromoCode(OrderViewModel orderViewModel) {
//your processing code
return Content("Promo has been applied");
}
View
#model NTC.PropertySearch.Models.OrderViewModel
#using (Ajax.BeginForm("ApplyPromoCode", "OrderSummary", new AjaxOptions { UpdateTargetId = "pcode" }))
{
<div id="promo">
<table>
<td>
#Html.LabelFor(m => m.PromoCode)
</td>
<td>
#Html.TextBoxFor(m => m.PromoCode)
</td>
<td>
#Html.ValidationMessageFor(m => m.PromoCode)
</td>
<td>
<input type="submit" value="Apply Promo Code" />
</td>
<td>
<div id="pcode"></div>
</td>
</table>
</div>
}
Instead of returning a PartialView you can always return a JSON object/array or some XML and use jQuery/JavaScript on your callback function to update the values of your input fields.
Here's an example of some code I use to return JSON from a Controller:
public ActionResult CurrentTags(int entityID)
{
Entity entity = db.Entity.Find(entityID);
var tags = from tag in entity.Tag
select new
{
id = tag.Name,
text = tag.Name
};
return this.Json(tags, JsonRequestBehavior.AllowGet);
}
My problem is in view...Please give me new view which suits my database and action.
My details table:
Passing request id using html action link:
#Html.ActionLink(item.Request_ID, "Details",new { requestid = item.Request_ID },null )
clicking on the link we should get details corresponding to the link from database.
Action method:
public ActionResult Details(string requestid)
{
var entities = new EmployDBEntities1();
var detailsModel = entities.Details.Single(e => e.Id == requestid);
return View(detailsModel);
//return View(entities.Details.ToList());
}
Hope my problem is returning view and designing view. My requirement is I want details for particular id and should display them in the below designed view. I am able to check the ids in var details model and then I have to read remaining fields from databse and disply the fields in my view.I am notable to do it. Please help me.
View:
model IEnumerable<Approvals.Models.Detail>
#{
ViewBag.Title = "Details";
//Layout = "~/Views/Shared/_Layout.cshtml";
}
#section Header {
#Html.ActionLink("Back", "PendingRequests", "Account", null, new { data_icon = "arrow-l", data_rel = "back" })
<h1>#ViewBag.Title</h1>
#Html.ActionLink("Log Off", "LogOff")
}
<head>
<link href="~/StyleSheet1.css" rel="stylesheet" type="text/css" />
</head>
<div data-role="collapsible" data-theme="b" data-content-theme="b">
<h3>Employee Details</h3>
<table class="td3">
#foreach (var item in Model) {
<tr>
<td>Employee ID</td>
<td>#Html.Encode(item.EmpID)</td>
</tr>
<tr>
<td>Short ID</td>
<td>
#Html.Encode(item.ShortID)
</td>
</tr>
<tr>
<td>Grade</td>
<td>#Html.Encode(item.Grade)</td>
</tr>
<tr>
<td>Vertical</td>
<td>#Html.Encode(item.Vertical)</td>
</tr>
<tr>
<td>Vertical Head</td>
<td>#Html.Encode(item.VerticalHead)</td>
</tr>
<tr>
<td>L1 Manager</td>
<td>#Html.Encode(item.L1_Manager)</td>
</tr>
<tr>
<td>L2 Manager</td>
<td>#Html.Encode(item.L2_Mnager)</td>
</tr>
<tr>
<td>CostCentre</td>
<td>#Html.Encode(item.CostCentre)</td>
</tr>
}
</table>
</div>
model Approvals.Models.Detail
#{
ViewBag.Title = "Details";
//Layout = "~/Views/Shared/_Layout.cshtml";
}
#section Header {
#Html.ActionLink("Back", "PendingRequests", "Account", null, new { data_icon = "arrow-l", data_rel = "back" })
<h1>#ViewBag.Title</h1>
#Html.ActionLink("Log Off", "LogOff")
}
<head>
<link href="~/StyleSheet1.css" rel="stylesheet" type="text/css" />
</head>
<div data-role="collapsible" data-theme="b" data-content-theme="b">
<h3>Employee Details</h3>
<table class="td3">
<tr>
<td>Employee ID</td>
<td>#Html.Encode(Model.EmpID)</td>
</tr>
<tr>
<td>Short ID</td>
<td>
#Html.Encode(Model.ShortID)
</td>
</tr>
<tr>
<td>Grade</td>
<td>#Html.Encode(Model.Grade)</td>
</tr>
<tr>
<td>Vertical</td>
<td>#Html.Encode(Model.Vertical)</td>
</tr>
<tr>
<td>Vertical Head</td>
<td>#Html.Encode(Model.VerticalHead)</td>
</tr>
<tr>
<td>L1 Manager</td>
<td>#Html.Encode(Model.L1_Manager)</td>
</tr>
<tr>
<td>L2 Manager</td>
<td>#Html.Encode(Model.L2_Mnager)</td>
</tr>
<tr>
<td>CostCentre</td>
<td>#Html.Encode(Model.CostCentre)</td>
</tr>
</table>
</div>
Instead of var type for detailsModel object give type what is bound to view i.e. IEnumerable of Approvals.Models.Detail in "Details" action.
your view name should match action name if not supplied in return View(). else return View("xxx", detailsModel ) in "Details" action.
I am using MVC4/EF and I have four cascading dropdownlist and I got it working the first time. So when the page is rendered first time, I am able to select the first dropdown and filter the result on the second and by selecting second dropdowm the third dropdwon is filtered and fourth and based on the fourth drop down I populate a edit view. But when I go back and change the selection in the first drop down, it is filtering the second drop down but not resetting the third, fourth dropdwon list and the edit partial view. Here is teh first dropdwon partial view code.
CampusUsercontrol.cshtml
#model RHMS.Models.RoomEditor
#using (Ajax.BeginForm("SelectCampus", "RoomEditor", new AjaxOptions { UpdateTargetId = "Buildings" }))
{
#Html.DropDownListFor(
m => m.SelectedCampusID,
new SelectList(Model.Campuses,"CampusId", "Name"),
string.Empty
)
}
<script type="text/javascript">
$('#SelectedCampusID').change(function () {
$(this).parents('form').submit();
});
</script>
Index.cshtml
#model RHMS.Models.RoomEditor
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<table cellpadding="0" cellspacing="4" border="0">
<tr>
<td>Campus </td>
<td> :</td>
<td>#Html.Partial("CampusUserControl", Model)</td>
</tr>
<tr>
<td>Building </td>
<td> :</td>
<td><div id="Buildings">#Html.Partial("BuildingUserControl", Model)</div></td>
</tr>
<tr>
<td>Floor </td>
<td> :</td>
<td><div id="Floor">#Html.Partial("FloorsUserControl", Model)</div></td>
</tr>
<tr>
<td>Room </td>
<td> :</td>
<td><div id="Room">#Html.Partial("RoomUserControl", Model)</div></td>
</tr>
</table>
<div id="RoomInfo">
#Html.Partial("RoomInfoUserControl", Model)
</div>
Please help me how to refresh the other partial views when the first one is changed.
Looks like this part of your javascript code is beeing executed only on the first load of the page
<script type="text/javascript">
$('#SelectedCampusID').change(function () {
$(this).parents('form').submit();
});
</script>
try wiring the change event for #SelectedCampusID using Jquery's on binding. You might also have to do the same for the other dropdowns.
I have a view in 2 sections.
The top section I input fields and submit to save them.
In the second section I have an autocomplete textbox. I select an item in autocomplete, and when I click submit I want to add that item to a datatable.
So for the first part when I click submit I save the details via a HttpPost method on the controller.
For the second part I intend to save it via an Ajax call for the controller and then bring back a partial view with the results. I have not coded the partial view yet, that is next.
Now I am new to Ajax.BeginForm and I am struggling with it.
I was hoping that the submit button inside the Ajax.BeginForm would only apply to that part of the form.
But in fact it calls the HttpPost method for the whole form.
So how do I fix this?
My view looks like;
#using ITOF.HtmlHelpers
#model ITOF.Models.OngoingContractViewModel
#{
ViewBag.Title = "EditOngoingContractDetails";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#using (Html.BeginForm("EditOngoingContractDetails", "Contract", FormMethod.Post,
new { enctype = "multipart/form-data" }))
{
#Html.ValidationSummary(true)
#Html.HiddenFor(model => model.Contract.ContractId)
<h1>Edit Ongoing Contract Details</h1>
<fieldset>
<legend>#Model.Contract.Heading</legend>
<p>Where you see <span class="error">*</span> you must enter data.</p>
<table>
<tr>
<td style="text-align: right">
#Html.LabelFor(model => model.Contract.EndDate)
</td>
<td>
#Html.EditorFor(model => model.Contract.EndDate)
</td>
</tr>
<tr>
<td style="text-align: right">
#Html.LabelFor(model => model.Contract.Organogramme)
</td>
<td>
<input type="file" id="PDF" name="file" />
#Html.HiddenFor(model => model.Contract.Organogramme)
</td>
</tr>
#if (!string.IsNullOrWhiteSpace(Model.Contract.Organogramme))
{
<tr>
<td></td>
<td>
The current organogramme is <span class="HighlightTextRed">#Model.GetOrganogrammeName()</span>
for the contract <span class="HighlightTextRed">#Model.Contract.ContractName</span><br/>
Click here to see the last saved organogramme
</td>
</tr>
}
<tr>
<td style="text-align: right">
#Html.LabelFor(model => model.Contract.AssistantRLOManagerId)
</td>
<td>
#Html.DropDownListFor(model => model.Contract.AssistantRLOManagerId, Model.AssistantRloManagerSelectList, "--N/A--")
</td>
</tr>
#if (this.TempData["SuccessMessage"] != null)
{
<tr>
<td colspan="2" class="success">#this.TempData["SuccessMessage"].ToString()</td>
</tr>
}
<tr>
<td colspan="2" style="padding-top: 20px; text-align: center;"><input type="submit" value="Save" /></td>
</tr>
</table>
</fieldset>
<fieldset>
<legend>Add an existing Site to this contract: </legend>
#using (Ajax.BeginForm("AddExistingSite", new AjaxOptions { UpdateTargetId = "siteRows" }))
{
<input type="text" name="q" style="width: 800px"
data-autocomplete="#Url.Action("SiteSearch", "DataService", new { contractId = #Model.Contract.ContractId })" />
<input type="submit" value="Add site to contract" />
}
#if (Model.SiteList.Count > 0)
{
<table id="siteDataTable" class="display">
<thead>
<tr>
<th>Main Site?</th>
<th>Type</th>
<th>Address</th>
<th>Map</th>
<th>Telephone</th>
<th>Email</th>
</tr>
</thead>
<tbody id="siteRows">
#foreach (var item in Model.SiteList)
{
<tr id="#item.SiteContract.SiteContractId">
<td>#item.SiteContract.MainSiteFlag</td>
<td>#item.Site.SiteType</td>
<td>#item.Site.Address</td>
<td>#item.Site.MapUrl</td>
<td>#item.Site.Telephone</td>
<td>#item.Site.Email</td>
</tr>
}
</tbody>
</table>
<div class="add_delete_toolbar" />
}
#Html.ListLink("Back to List")
</fieldset>
}
Oh no, you just cannot nest HTML forms. That's not supported. You will have to rethink your design. This really has absolutely nothing to do with ASP.NET MVC and things like Html.BeginForm or Ajax.BeginForm. The HTML specification simply tells you that the <form> tag cannot be nested and if you nest it you will get undefined behavior that could vary between browsers.
For example you could implement the autocomplete functionality using jquery UI autocomplete plugin and get rid of the Ajax.BeginForm.
I have a view like:
#model IEnumerable<VectorCheck.Models.Invoice>
#{
ViewBag.Title = "Exportable Invoices";
}
<script src="../../Scripts/jquery-1.7.1.min.js" type="text/javascript"></script>
<script src="../../Scripts/jquery-ui-1.8.16.min.js" type="text/javascript"></script>
<script src="../../Scripts/Views/Export/index.js" type="text/javascript"></script
<header class="header">
<div class="headerText">
<h1>Exportable Invoices</h1>
</div>
</header>
#using (Html.BeginForm("Export", "Export")) {
<table>
<tr class="mainheader">
<th>Invoice Number</th>
<th>Date</th>
<th>Organisation</th>
<th>Total (Excl GST)</th>
<th>Status</th>
<th>Exported Date</th>
<th>
<select id="expenseSelect"></select>
<input type="submit" id="btnexport" value="Export" />
</th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.InvoiceNumber)
</td>
<td>
#Html.DisplayFor(modelItem => item.InvoiceDate, "{0:D}")
</td>
<td>
#Html.DisplayFor(modelItem => item.Organisation.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.TotalExcludingGst)
</td>
<td>
#Html.DisplayFor(modelItem => item.Status)
</td>
<td>
#Html.DisplayFor(modelItem => item.ExportedDateTime)
</td>
<td class="centered">
<input type="checkbox" class="exportcheckbox" data-invoiceid=#item.InvoiceId />
</td>
</tr>
}
</table>
}
<div>
#Html.ActionLink("Back to Summary", "Index", "Invoice")
</div>
Ok, so see how each checkbox has an attribrute data-invoiceid=#item.InvoiceId. Well I'm trying to get to an action method the Ids of all the invoices that have had their checkboxes checked. Also I'm trying to get the id of the selectlist expenseSelect which has options added to it on page load via jquery. I managed to achieve this with jquery and then sending the data with a $.post. The problem is in the file I'm sending the info to:
public ActionResult Export()
{
...
var csvData = _utility.GetCsvData(data);
return File(Encoding.UTF8.GetBytes(csvData), "text.csv", "invoices.csv");
}
brings up a save/open file dialog. I'm been informed this won't work for the jquery ajax call and I need to post the info back using a submit.
That's fine but now I have no idea how to send the select id and a list of the ids of the checked checkboxes to the method. Can anybody show me how to go about this?
You don't need any HTML5 data-* attributes since they are not sent to the server when you submit the form. In order to send their values you will have to use AJAX but this won't work with file downloads. So simply give your checkboxes a name:
<td class="centered">
<input type="checkbox" class="exportcheckbox" name="ids" value="#item.InvoiceId" />
</td>
and then on the server the default model binder will automatically construct an array of the ids of the checked items:
[HttpPost]
public ActionResult Export(int[] ids)
{
byte[] data = ...
return File(data, "text/csv", "invoices.csv");
}
Depending on the type of InvoiceId you might need to adjust the type of the action argument.
Radically changing my answer...
You could dynamically add a hidden IFRAME to your page. The IFRAME src can take your selected "ids" as a querystring parameter. This should get your your download dialog.
Got some help with the jquery from here: JQuery: Turn array input values into a string optimization
var selectedIdsArray = $(":checked").map(function(){return $(this).attr('data-invoiceid');});
var url = '#Url.Action("Export", "Export")?csv=' selectedIdsArray.get().join(',');
$('body').append("<iframe style='visibility:hidden' src='"+url +"'/>");