ASP.NET MVC Passing Data from View to Controller - asp.net-mvc

I have a view with a grid that contains items added to a workstation. The user can select an item from a drop down list and click an action link which calls a controller that adds that item to the workstation. I can make it work by reading the FormCollection object in the Post action of the controller.
<p>
<% using(Html.BeginForm("AddItem", "Home")) { %>
<label for="ItemID">Item:</label>
<%= Html.DropDownList("ItemID", Model.ItemsList) %>
<%= Html.Hidden("WorkstationID", Model.Workstation.RecordID) %>
<input type="submit" value="Submit" />
<% } %>
</p>
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult AddItem(FormCollection formValue)
{
long workstationId = Convert.ToInt64(formValue["WorkstationID"]);
long itemId = Convert.ToInt64(formValue["ItemID"]);
Workstation workstation = itilRepository.FindWorkstation(workstationId);
Item item = itilRepository.FindItem(itemId);
itilRepository.AddItem(workstation, item);
itilRepository.Save();
return Content("Item added successfully!");
}
What I want to do is be able to submit the two parameters the workstationId and itemId to the controller using Ajax.ActionLink and have the new item that was added get inserted into the grid. I am rendering the grid like this:
<table>
<tr>
<th></th>
<th>
Name
</th>
<th>
Service Tag
</th>
<th>
Serial Number
</th>
</tr>
<% foreach (var item in Model.Items) { %>
<tr>
<td>
<%= Html.ActionLink("Edit", "ItemEdit", new { id = item.RecordID }) %> |
<%= Html.ActionLink("Details", "ItemDetails", new { id = item.RecordID })%>
</td>
<td>
<%= Html.Encode(item.Name) %>
</td>
<td>
<%= Html.Encode(item.ServiceTag) %>
</td>
<td>
<%= Html.Encode(item.SerialNumber) %>
</td>
</tr>
<% } %>
</table>
The problem I have is when I submit using the ActionLink I can't figure out how to pass in the parameters to the controller and how to update the grid without reloading the entire view.
I would really appreciate some help with this or even a link to a tutorials that does something similar.
Thank You!
This is the working version, the one problem is that when the controller returns the partial view that is all that gets rendred the actual page is gone.
<% using (Ajax.BeginForm("AddItem", null,
new AjaxOptions
{
UpdateTargetId = "ResultsGoHere",
InsertionMode = InsertionMode.Replace
},
new { #id = "itemForm" } ))
{ %>
<label for="ItemID">Item:</label>
<%= Html.DropDownList("itemId", Model.ItemsList) %>
<%= Html.Hidden("workstationId", Model.Workstation.RecordID) %>
Submit
<div id="ResultsGoHere">
<% Html.RenderPartial("WorkstationItems", Model.Items); %>
</div>
<% } %>
Not sure what the cause is, the replace was working correctly before but the controller wasn't getting the drop down value. Now the controller is getting the value but the partial view that is returned replaces the entire page.
The Action Method:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult AddItem(string workstationId, string itemId)
{
long lworkstationId = Convert.ToInt64(workstationId);
long litemId = Convert.ToInt64(itemId);
Workstation workstation = itilRepository.FindWorkstation(lworkstationId);
Item item = itilRepository.FindItem(litemId);
IQueryable<Item> items = itilRepository.AddItem(workstation, item);
itilRepository.Save();
return PartialView("WorkstationItems", items);
}
This is the HTML for the View that does all the work:
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<ITILDatabase.Models.WorkstationFormViewModel>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Workstation Details
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<script src="/Scripts/MicrosoftAjax.js" type="text/javascript"></script>
<script src="/Scripts/MicrosoftMvcAjax.js" type="text/javascript"></script>
<link type="text/css" href="/../Content/css/ui-lightness/jquery-ui-1.7.2.custom.css" rel="stylesheet" />
<script type="text/javascript" src="/../Content/js/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="/../Content/js/jquery-ui-1.7.2.custom.min.js"></script>
<h2>
Workstation Details</h2>
<fieldset>
<legend>Fields</legend>
<p>
Record ID:
<%= Html.Encode(Model.Workstation.RecordID) %>
</p>
<p>
Name:
<%= Html.Encode(Model.Workstation.Name) %>
</p>
<p>
Description:
<%= Html.Encode(Model.Workstation.Description) %>
</p>
<p>
Site:
<%= Html.Encode(Model.Workstation.Site.Name) %>
</p>
<p>
Modified By:
<%= Html.Encode(Model.Workstation.ModifiedBy) %>
</p>
<p>
Modified On:
<%= Html.Encode(String.Format("{0:g}", Model.Workstation.ModifiedOn)) %>
</p>
<p>
Created By:
<%= Html.Encode(Model.Workstation.CreatedBy) %>
</p>
<p>
Created On:
<%= Html.Encode(String.Format("{0:g}", Model.Workstation.CreatedOn)) %>
</p>
</fieldset>
<fieldset>
<legend>People</legend>
<% Html.RenderPartial("WorkstationPeople", Model.People); %>
</fieldset>
<fieldset>
<legend>Positions</legend>
<% Html.RenderPartial("WorkstationPositions", Model.Positions); %>
</fieldset>
<fieldset>
<legend>Items</legend>
<% using (Ajax.BeginForm("AddItem", "Home", null,
new AjaxOptions
{
UpdateTargetId = "ResultsGoHere",
InsertionMode = InsertionMode.Replace
},
new { #id = "itemForm" } ))
{ %>
<label for="ItemID">Item:</label>
<%= Html.DropDownList("itemId", Model.ItemsList) %>
<%= Html.Hidden("workstationId", Model.Workstation.RecordID) %>
Submit
<div id="ResultsGoHere">
<% Html.RenderPartial("WorkstationItems", Model.Items); %>
</div>
<% } %>
</fieldset>
<br />
<p>
<%=Html.ActionLink("Edit", "WorkstationEdit", new { id = Model.Workstation.RecordID }) %>
|
<%=Html.ActionLink("Back to List", "Index") %>
</p>
</asp:Content>

What result are you expecting from the AJAX call?
You could use the AjaxHelper object's helper methods instead of the HtmlHelper to render the link. For example, to get new content with an AJAX HttpPOST call and insert it into a <div> with the id set to ResultsGoHere you render the following link:
<%= Ajax.ActionLink("Edit", "ItemEdit",
new {
itemId = item.RecordId,
workstationId = myWorkStationId
},
new AjaxOptions {
HttpMethod="POST",
UpdateTargetId="ResultsGoHere",
InsertionMode = InsertionMode.Replace
}) %>
In your AcionMethod, you can simply test on Request.IsAjaxRequest() to decide what to return:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult ItemEdit(string itemId, string workstationId) {
// edit the item and get it back
if (Request.IsAjaxRequest()) {
return PartialView("SingleItem", item);
}
return RedirectToAction("ItemEdit", new { itemId = item.RecordId, workstationId = workstationId });
}
// fallback for get requests
public ActionResult ItemEdit(string itemId, string workstationId)
{
// do stuff and return view
}

This is how you could do it using the Ajax.BeginForm() method instead:
<% using (Ajax.BeginForm("ItemEdit", null, new AjaxOptions
{
UpdateTargetId = "ResultsGoHere",
InsertionMode = InsertionMode.Replace
}, new { #id = "itemForm" } )
{ %>
<p>
<%= Html.DropDownList("itemId") %></p>
<p>
<%= Html.DropDownList("workstationId") %></p>
<p>
Submit
</p>
<% } %>
Please note that the code is in its current state in no way fully functional - the dropdownlists don't get their items from anywhere, there is no <div> to take care of the results from the AJAX request, and the onclick attribute on the link that submits the form requires that jQuery is included (in which case it is way better to give the link an id and add a click() event handler to it from a separate js file...)
EDIT: Oh, and I haven't verified that it is OK to pass a null value to the routeValues parameter. If not, just supply the controller and action names, and you'll be fine.

how can you pass the model from the view to the post create action of the controller using ajax.actionlink?

Here, as of my knowledge, we can pass data from View to Controller in two ways...
Using Formcollection built in keyword like this..
[HttpPost]
public string filter(FormCollection fc)
{
return "welcome to filtering : "+fc[0];
(or)
return "welcome to filtering : "+fc["here id of the control in view"];
}
FormCollection will work only when you click any button inside a form. In other cases it contains only empty data
Using model class
[HttpPost]
public string filter(classname cn)
{
return "welcome to filtering : "+cn.Empid+""+cn.Empname;
}

This is how you will be able to send multiple parameters through actionLink.
For this situation please refer to the code below:
#Html.ActionLink("Link text", "Action Name", null, routeValues: new { pram_serviceLine = Model.ServiceLine_ID, pram_Month = Model.Month, pram_Year = Model.Year, flag = "ROTATION" }
Reply if it works.

Related

Deleting record using MVC Delete View

What I am trying to do is I am Listing all the record and then provide option to delete the record. When User clicks on Delete Link on Index page he is redirected to Delete Confirmation Page( Delete View created by MVC framework), now what I was expecting was when I click on Submit button on the Delete View it will come to my Delete Action of Controller with the object that needs to be deleted. But the problem is I am getting a object but all the properties are set to null.
Below is the code:
//GET
public ActionResult DeleteUser (long id )
{
return View(_repository.GetUserById(id));
}
//POST
[HttpPost]
public ActionResult DeleteUser (UserDTO user)
{
_repository.DeleteUser(user.UserId);
/
return RedirectToAction("Index");
}
I was expecting that one submit is clicked then Second (HttpPost) method will be called and user will be filled with the values, but that is not happening..
can anyone tell me what wrong am I doing ???
This is my Delete View Code
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<RepositoryPatternSample.DTOs.UserDTO>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
DeleteUser
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>DeleteUser</h2>
<h3>Are you sure you want to delete this?</h3>
<fieldset>
<legend>UserDTO</legend>
<div class="display-label">UserId</div>
<div class="display-field"><%: Model.UserId %></div>
<div class="display-label">Username</div>
<div class="display-field"><%: Model.Username %></div>
<div class="display-label">FirstName</div>
<div class="display-field"><%: Model.FirstName %></div>
<div class="display-label">LastName</div>
<div class="display-field"><%: Model.LastName %></div>
</fieldset>
<% using (Html.BeginForm()) { %>
<p>
<input type="submit" value="Delete User" /> |
<%: Html.ActionLink("Back to List", "Index") %>
</p>
<% } %>
</asp:Content>
Your properties are out of the form post. That's why you see the model null.
Personally instead of passing all the model properties I would pass only the id.
Something like that
<% using (Html.BeginForm()) { %>
<p>
<%: Html.HiddenFor(model=> model.UserId) %>
<input type="submit" value="Delete User" /> |
<%: Html.ActionLink("Back to List", "Index") %>
</p>
<% } %>
and your controller would be
[HttpPost]
public ActionResult DeleteUser (int userId)
{
_repository.DeleteUser(userId);
return RedirectToAction("Index");
}

MVC: Form not rendering in partial view

I have a form with tabs. Subordinate to each tab is a partial view.
When the user submits to save changes, I want to call a method for that partial view, so for the partial view I put in <% using (Html.BeginForm(...) %>. But this gets ignored and clicking submit will call the method associated with the container view instead. Why is this, and how do I get this to work?
The View looks like;
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Employee.Master" Inherits="System.Web.Mvc.ViewPage<SHP.WebUI.Models.HolidayRequestViewModel>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
HolidayRequest
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="EmployeeContent" runat="server">
<% using (Html.BeginForm()) {%>
<%: Html.AntiForgeryToken() %>
<h2>Holiday Request</h2>
<p>You have <%: Html.DisplayFor(model => model.DaysAvailableThisYear) %> days left annual leave for this year
and <%: Html.DisplayFor(model => model.DaysAvailableNextYear) %> days left for next year.</p>
<p>If your request is approved and exceeds the number of days left, then those extra days will not be paid.</p>
<div id="tabs">
<ul>
<li>Approver</li>
<li>Single Date</li>
<li>Date Range</li>
</ul>
<div id="tabs-1">
<% Html.RenderPartial("GetApproverTab", Model); %>
</div>
<div id="tabs-2">
<% Html.RenderPartial("GetSingleDateTab", Model); %>
</div>
<div id="tabs-3">
<% Html.RenderPartial("GetDateRangeTab", Model); %>
</div>
</div>
<%: Html.HiddenFor(x => x.EmployeeId) %>
<% } %>
</asp:Content>
The partial view looks like;
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<SHP.WebUI.Models.HolidayRequestViewModel>" %>
<% using (Html.BeginForm("GetSingleDateTab", "Employee", FormMethod.Post, new { id = "frmSingleDate" }))
{ %>
<p>Enter your day or part day of Annual Leave here.</p>
<table>
<tr>
<td align="right">Date:</td>
<td><%: Html.EditorFor(x => x.SingleDate) %></td>
</tr>
<tr>
<td align="right">Morning Only:</td>
<td><%: Html.CheckBoxFor(x => x.MorningOnlyFlag) %></td>
</tr>
<tr>
<td align="right">Afternoon Only:</td>
<td><%: Html.CheckBoxFor(x => x.MorningOnlyFlag) %></td>
</tr>
<tr>
<td colspan="2" align="center"><input type="submit" value="Save" /></td>
</tr>
</table>
<% } %>
and the controller looks like;
#region Employee Holiday Request
public ActionResult HolidayRequest()
{
return View(new HolidayRequestViewModel(Employee.GetLoggedInUser().EmployeeId));
}
[HttpPost] // This is the method that gets executed
public ActionResult HolidayRequest(HolidayRequestViewModel hrvm)
{
if (ModelState.IsValid)
{
hrvm.Update();
return View(new HolidayRequestViewModel(hrvm.EmployeeId));
}
return View(hrvm);
}
[HttpPost] // This is the method I want to get executed.
public ActionResult GetSingleDateTab(HolidayRequestViewModel hrvm)
{
if (ModelState.IsValid)
{
hrvm.Update();
return View(new HolidayRequestViewModel(hrvm.EmployeeId));
}
return View("GetSingleDateTab", hrvm);
}
#endregion
You can't have nester forms in html.
I discover an unbelievable solution. Just insert a <script> tag above the <form> tag.
<script type="text/javascript">
// don't remove <script> tag
</script>
<form ....

Getting 404 on a simple controller

I'm creating a simple form to upload a file (which can be given a friendly name).
I've gone over this code time and time again, but always get a 404 when the form posts to /MyEntities/Add (this is a post-only URL on purpose).
Any thoughts would be much appreciated - I simply can't see what I've done wrong.
The controller:
public class MyEntitiesController : Controller
{
private DataFilesComparisonRepository repository = new DataFilesComparisonRepository();
public ActionResult Index()
{
List<MyEntitiesDataset> datasets = repository.GetMyEntitiesDatasets();
return View(datasets);
}
[HttpPost]
public ActionResult Add(HttpPostedFileBase postedFile, string friendlyName)
{
repository.AddMyEntities(friendlyName, postedFile.FileName, postedFile.InputStream);
return RedirectToAction("Index");
}
}
And the view:
<%# Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<List<MyEntitiesDataset>>" %>
<%# Import Namespace="DataFilesComparison.Models" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
The Title
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<% Html.BeginForm("Add", "MyEntities", FormMethod.Post, new { enctype = "multipart/form-data" }); %>
<p>
<input type="file" name="postedFile" />
<label for="friendlyName">Friendly Name:</label>
<%= Html.TextBox("friendlyName") %>
<input type="submit" value="Add" />
</p>
<% Html.EndForm(); %>
<% if (Model == null || Model.Count == 0) { %>
<p>No datasets found.</p>
<% } else { %>
<ul>
<% foreach (MyEntitiesDataset dataset in Model) { %>
<li>
<%= dataset.Name %>
[<%= Html.ActionLink("X", "Delete", new { ID = dataset.ID })%>]
</li>
<% } %>
</ul>
<% } %>
</asp:Content>
The model you are passing into the view is not the same of the same type that you are posting back into the Add() method, which may be confusing the default routing settings. Although I see you have been explicit about which method to call, I have had problems like this before. Maybe try creating a ViewModel with the properties you need for the GET and POST, then using them in both the View and the Controller methods. Like this:
Model
public MyViewModel
{
public List<MyEntitiesDataset> Datasets {get; set;}
public HttpPostedFileBase PostedFile {get; set;}
public string FriendlyName {get; set;}
}
Controller Methods
public ActionResult Index()
{
MyViewModel model = new MyViewModel();
model.Datasets = repository.GetMyEntitiesDatasets();
return View(datasets);
}
[HttpPost]
public ActionResult Add(MyViewModel model)
{
repository.AddMyEntities(model.FriendlyName, Model.PostedFile.FileName, Model.postedFile.InputStream);
return RedirectToAction("Index", model);
}
View
%# Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MyViewModel>" %>
<%# Import Namespace="DataFilesComparison.Models" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
The Title
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<% Html.BeginForm("Add", "MyEntities", FormMethod.Post, new { enctype = "multipart/form-data" }); %>
<p>
<input type="file" name="postedFile" />
<label for="Model.FriendlyName">Friendly Name:</label>
<%= Html.TextBoxFor(m => m.FriendlyName) %>
<input type="submit" value="Add" />
</p>
<% Html.EndForm(); %>
<% if (Model.Datasets == null || Model.Datasets.Count == 0) { %>
<p>No datasets found.</p>
<% } else { %>
<ul>
<% foreach (var dataset in Model.Datasets) { %>
<li>
<%= dataset.Name %>
[<%= Html.ActionLink("X", "Delete", new { ID = dataset.ID })%>]
</li>
<% } %>
</ul>
<% } %>
</asp:Content>
You might have to play around with the file uploader (not sure if there is an Html.FileFor, but hopefully you get the idea!
Good luck.

Asp.Net Axaj.BeginForm & UpdateTargetId not working

I have this in HomeController:
public ActionResult Details(string id)
{
var customer = Customers.GetCustomersById(id);
return PartialView("CustomerDetails", customer);
}
And this in Index.aspx:
<div>
<% using (Ajax.BeginForm("Details", new AjaxOptions
{
UpdateTargetId = "customerDetails",
InsertionMode = InsertionMode.Replace,
HttpMethod = "POST"
}))
{ %>
<p>
Customer:
<%=Html.DropDownList("id")%></p>
<p>
<input type="submit" value="Details" /></p>
<% } %>
</div>
<div id="customerDetails">
</div>
And finally in CustomerDetails.ascx I have:
<fieldset>
<legend>Fields</legend>
<p>
Name:
<%= Html.Encode(Model.Name) %>
</p>
<p>
Credit:
<%= Html.Encode(Model.Credit) %>
</p>
<p>
CustomerID:
<%= Html.Encode(Model.CustomerID) %>
</p>
</fieldset>
<p>
<%=Html.ActionLink("Edit", "Edit", new { /* id=Model.PrimaryKey */ }) %> |
<%=Html.ActionLink("Back to List", "Index") %>
</p>
CustomerDetails.ascx was generated by right clicking on the Details-method and choosing "Add View", and selecting partial view and strongly typed view.
I'd want this to update the customer details in "Ajax-manner" inside a div called "customerDetails" inside Index.html. The problem is that after pressing Details-button, a new page is opened where with the correct details. The output page has no master page colors or layouts.
If I debug at Details-method, the contents of customer object is correct.
Any help appreciated!
/pom
The most likely culprit is that you aren't including MicrosoftAjax.js and MicrosoftMvcAjax.js on the page. This causes the javascript to fail because it can't find the necessary functions and the form submits normally instead through Ajax.

Ajax.ActionLink, how to send the selected object in the partial view? asp.net mvc

I guess this is a noob question, but here it comes:
I have a list of products:
<% foreach (var item in Model) { %>
<tr>
<td>
<%= Html.Encode(item.code) %>
</td>
<td>
<%= Html.Encode(String.Format("{0:g}", item.date)) %>
</td>
<td>
<%= Html.Encode(item.category) %>
</td>
<td>
<%= Html.Encode(item.description) %>
</td>
<td>
<%= Html.Encode(String.Format("{0:F}", item.price)) %>
</td>
......
}
And a partial view after all of these (in the same page):
<div id="productForEdit">
<fieldset>
<legend>Your Selected Product</legend>
<% Html.RenderPartial("~/Views/Products/Edit", productObject); %>
</fieldset>
</div>
How do I use Ajax.ActionLink, so that when I will click the description of a product, the product will be plugged in the Partial View from the bottom of the page?
I tried some combination with UpdateTargetId="productForEdit", but I had no success.
The purpose is to have a quick edit tool in the page.
I think this should work:
<td>
<%= Ajax.ActionLink(Html.Encode(item.description), /* link text */
"GetProduct", /* action name */
"Product", /* controller name */
new { productCode = Model.code }, /* route values */
new AjaxOptions() { InsertionMode = InsertionMode.Replace,
UpdateTargetId = "productForEdit" }) %>
</td>
This does expect a ProductController with an action named GetProduct, which takes a parameter productCode. Have this action return the view "Products/Edit".
You could also pass the whole product as a parameter to the action method, but that changes nothing to the basic idea. Good luck!

Resources