asp.net mvc razor getting id with post - c#

how can i get the querystring id in there? is there any way
#using (Html.BeginForm("InformVendor", "Procurement",new {id="querystring Mode = "Inform" }, FormMethod.Post))
{
<tr>
<td>
#Html.DropDownListFor(m=>m.VendorId,new MultiSelectList(Model.VendorDropdownlist, "CustomerId", "ContactName"))
</td>
<td>
#Html.CheckBoxFor(m => m.IsEmail)
</td>
</tr>
<tr>
<td>
<input type="submit" id="btnsubmit" value="Nominate Vendor" />
</td>
<td></td>
</tr>
}

The easiest way is to have your id field be hidden. This way the user doesn't see the ID field but your post back controller does.
#Html.HiddenFor(x => x.YourID)

If you add the Id to your view model and render it as a hidden field.
#Html.HiddenFor(m => m.Id)
You will be able to retrieve it like this instead of using the querystring.
public ActionResult InformVendor(AViewModel model)
{
var Id = model.Id;
}

Related

How can I use textbox value as parameter?

I want to send NumberBox Inputted values to the controller.
I can send the numberBox value to the controller in the bellow way
<input type="button" value="+" onclick="location.href='#Url.Action("GetProductInReceipt", "Sale")?id=' + document.getElementById('SaleQuantity#(i)').value" />
or
<input type="button" value="+" onclick="location.href='#Url.Action("GetProductInReceipt", "Sale")?id=' + $('#SaleQuantity#(i)').val()" />
Both ways send the NumberBox value from this code
but I need to send one more parameters to the controller which I can send seperately like this,
+
How can I send both parameters together?
I need to send both parameters using any one way.
Here is my code
#{ var i = 0;}
<tbody id="myTable">
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.ProductCode)
</td>
<td>
#Html.DisplayFor(modelItem => item.ProductName)
</td>
<td>
#Html.DisplayFor(modelItem => item.SellingPrice)
</td>
<td>
<input type="number" class="numberInput" name="SaleQuantity#(i)" id="SaleQuantity#(i)" min="1">
<td> +
</td>
</tr>
i++;
}
</tbody>
</table>
I want to do it without ajax call. Simply how can I send both parameters together?

Html Table with button per row doesn't pass data to the controller

Context
I'm developing a form in ASP.NET MVC 4 with Bootstrap 3 which displays an entity framework derived table. The table is read-only except that there is a button in the first column of each row allowing that row to be deleted.
My ViewModel:
public class SearchQueueViewModel
{
public List<SearchURL> SearchUrls { get; set; }
[Url(ErrorMessage = "Please provide a valid url")]
[MaxLength(500, ErrorMessage = "Url must be 500 characters or less")]
[Required]
public string NewUrl { get; set; }
}
The table is coded like this:
#model SearchQueueViewModel
#foreach (UserInterface.Models.SearchURL row in Model.SearchUrls)
{
<tr>
<td class="col-md-1 text-center">
#using (Html.BeginForm("delete", "home", FormMethod.Post, new { #class = "form-inline" }))
{
#Html.AntiForgeryToken()
<input type="hidden" value="#row" name="searchURL" />
<button type="submit" class="btn btn-xs">X</button>
}
</td>
<td class="col-md-2">#Html.DisplayFor(m => row.URL)</td>
<td class="col-md-2">#row.DateAdded.ToString("d-MMM-yy HH:mm")</td>
<td class="col-md-1">#Html.DisplayFor(m => row.Status)</td>
<td class="col-md-1">#Html.DisplayFor(m => row.SearchStarted)</td>
<td class="col-md-1">#Html.DisplayFor(m => row.SearchCompleted)</td>
<td class="col-md-1">#Html.DisplayFor(m => row.NumberOfProductsSearched)</td>
<td class="col-md-1">#Html.DisplayFor(m => row.NumberOfProductsFound)</td>
<td class="col-md-2">#Html.DisplayFor(m => row.FailErrorMessage)</td>
</tr>
}
In the controller I have:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Delete(SearchURL searchURL)
{
context.SearchURLs.Remove(searchURL);
context.SaveChanges();
viewModel.SearchUrls = context.SearchURLs.ToList();
return View(viewModel);
}
Issue
The controller always receives a null object
Question
How do I get the searchURL object from the button-clicked row passed back to the controller correctly?
Note the for loop insted of foreach to enable model binding and the hidden fields to allow the values to be posted back to the controller. Change your view.
Your View:
#for (int i = 0; i < Model.SearchUrls.Count; i++)
{
<tr>
<td class="col-md-1 text-center">
#using (Html.BeginForm("delete", "home", FormMethod.Post, new { #class = "form-inline" }))
{
#Html.AntiForgeryToken()
#Html.HiddenFor(m=>Model.SearchUrls[i].SearchURLId)
<button type="submit" class="btn btn-xs">delete</button>
}
</td>
<td class="col-md-2">#Html.DisplayFor(m => Model.SearchUrls[i].SearchURLId.URL)</td>
<td class="col-md-2">#Model.SearchUrls[i].DateAdded.ToString("d-MMM-yy HH:mm")</td>
<td class="col-md-1">#Html.DisplayFor(m => Model.SearchUrls[i].Status)</td>
<td class="col-md-1">#Html.DisplayFor(m => Model.SearchUrls[i].SearchStarted)</td>
<td class="col-md-1">#Html.DisplayFor(m => Model.SearchUrls[i].SearchCompleted)</td>
<td class="col-md-1">#Html.DisplayFor(m => Model.SearchUrls[i].NumberOfProductsSearched)</td>
<td class="col-md-1">#Html.DisplayFor(m => Model.SearchUrls[i].NumberOfProductsFound)</td>
<td class="col-md-2">#Html.DisplayFor(m => Model.SearchUrls[i].FailErrorMessage)</td>
</tr>
}
And also change your Delete method.
public ActionResult delete(SearchQueueViewModel sm) // note this line
{
//your code
}
But the job is not finished yet. If I am not wrong now you are going to face issue with multiple submit button with identical property.
The best approach for your requirement is using javascript. You can have a look to this

MVC: Passing Value from View to Controller

I am trying to pass values from a view to a controller in MVC. I am using a ViewModel and normally the values would bind to the properties as long as the names are the same. However because the values are generated via a foreach loop the names of the values do not match the names of the properties in the view model.
I am working around this by assigning the values to a variable in Razor. However one of my values is in a text box on the form and the value is not being passed to the controller and I cannot work out why.
I get a null exception when clicking the button.
VIEW Code is below:
#model PagedList.IPagedList<Mojito.Domain.ViewModels.ShoppingCartProductItem>
#using System.Web.UI.WebControls
#using PagedList.Mvc;
<link href="~/Content/PagedList.css" rel="stylesheet" type="text/css" />
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Mojito Products</h2>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.FirstOrDefault().Description)
</th>
<th>
#Html.ActionLink("Price", "Index", new { sortOrder = ViewBag.SortByPrice, currentFilter = ViewBag.CurrentFilter })
</th>
<th>
#Html.DisplayNameFor(model => model.FirstOrDefault().Quantity)
</th>
<th>
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Description)
</td>
<td>
#Html.DisplayFor(modelItem => item.Price)
</td>
<td>
#Html.TextBoxFor(modelItem => item.Quantity)
</td>
<td>
#{string Description = item.Description;}
#{decimal Price = item.Price;}
#{int Quantity = item.Quantity; }
#using (Html.BeginForm("AddToCart", "ShoppingCart", FormMethod.Post))
{
<div class="pull-right">
#if (Request.Url != null)
{
<input type="text" hidden="true" name="Description" value=#Description />
<input type="text" hidden="true" name="Price" value=#Price />
<input type="text" hidden="true" name="Quantity" value=#Quantity />
#Html.Hidden("returnUrl", Request.Url.PathAndQuery)
<input type="submit" class="btn btn-success" value="Add to cart" />
}
</div>
}
</td>
</tr>
}
</table>
<div class="col-md-12">
Page #(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of #Model.PageCount
</div>
#Html.PagedListPager(Model, page => Url.Action("Index",
new { page, sortOrder = ViewBag.CurrentSort, currentFilter = ViewBag.CurrentFilter }))
Controller Code below
public ActionResult AddToCart(Cart cart, MojitoProduct product, string returnUrl, int Quantity =1)
{
if (product != null)
{
cart.AddItem(product, Quantity);
}
return RedirectToAction("Index", new { returnUrl });
}
Do not use foreach. Use a for-loop instead and within this, qualify the full path to your properties using the index.
Better yet: use a Edit- or DisplayTemplate for the ShoppingCartProductItem. This will also keep your path.
You have to use for loop instead of foreach:
#for (int i=0;i < Model.Count; i++)
{
<tr>
<td>
#Html.DisplayFor(modelItem => Model[i].Description)
</td>
<td>
#Html.DisplayFor(modelItem => Model[i].Price)
</td>
<td>
#Html.TextBoxFor(modelItem => Model[i].Quantity)
</td>
..........................
..........................
..........................
}
you can also post all using one form by posting List<ShoppingCartProductItem>, see Model Binding To A List
Your textboxes so values out of the form.
Try like below
#using (Html.BeginForm("AddToCart", "ShoppingCart", FormMethod.Post))
{
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Description)
</td>
<td>
#Html.DisplayFor(modelItem => item.Price)
</td>
<td>
#Html.TextBoxFor(modelItem => item.Quantity)
</td>
<td>
#{string Description = item.Description;}
#{decimal Price = item.Price;}
#{int Quantity = item.Quantity; }
<div class="pull-right">
#if (Request.Url != null)
{
<input type="text" hidden="true" name="Description" value=#Description />
<input type="text" hidden="true" name="Price" value=#Price />
<input type="text" hidden="true" name="Quantity" value=#Quantity />
#Html.Hidden("returnUrl", Request.Url.PathAndQuery)
<input type="submit" class="btn btn-success" value="Add to cart" />
}
</div>
</td>
</tr>
}
}
I resolved this in the short term by using new and forcing the name of the parameter.
#Html.HiddenFor(modelItem => t.NoOfUsers, new { Name = "NoOfUsers", id = "NoOfUsers" })

Getting response as null in http post method

I am using the following code:
Controller:
public ActionResult Update(int studentId = 0, int subjectId = 0)
{
Engine engine = new Engine(studentId, subjectId);
List<Chapter> chapterList = engine.GetChapters();
return View(chapterList);
}
[HttpPost]
public ActionResult Update(List<Chapter> model)
{
return View(model);
}
Update.cshtml:
#model IEnumerable<Chapter>
#{
ViewBag.Title = "Update";
}
<h2>
Update</h2>
#using (Html.BeginForm("Update", "StudyPlan", FormMethod.Post))
{
<fieldset>
<table>
#foreach (var item in Model)
{
<tr>
<td>
#item.name
</td>
<td>
#Html.CheckBoxFor(chapterItem => item.included)
</td>
</tr>
}
</table>
<input type="submit" value="submit" />
</fieldset>
}
I want when a user selects checkboxes, the response should come in httppost method of controller. But I am getting null value Update method. Am I doing something wrong
You need to use for instead of foreach. In that case checkbox will be rendered as
<input type='checkbox' name='Model[0].included'/>
<input type='checkbox' name='Model[1].included'/>
...
and then ModelBinder will successfully create model
Example:
#model List<Chapter>
#{
ViewBag.Title = "Update";
}
<h2>
Update</h2>
#using (Html.BeginForm("Update", "StudyPlan", FormMethod.Post))
{
<fieldset>
<table>
#for (int i =0;i<Model.Count;i++)
{
<tr>
<td>
#Model[i].name
</td>
<td>
#Html.CheckBoxFor(chapterItem => Model[i].included)
</td>
</tr>
}
</table>
<input type="submit" value="submit" />
</fieldset>
}
PS. in that example Model changed to List<> from IEnumerable
It happens because MVC analyze expression in CheckBoxFor method. And it this expression is array accessor, then it generates different control name. And based on Name ModelBinder successfully creates List<>
As Sergey suggested, use a for loop, but try this:
#for (int i =0;i<Model.Count;i++)
{
<tr>
<td>
#Html.HiddenFor(m => m[i].id)
#Html.DisplayFor(m => m[i].name)
</td>
<td>
#Html.CheckBoxFor(m => m[i].included)
</td>
</tr>
}

Saving multiple objects from MVC view

I'm writing my first MVC3 application which is a simple order tracking application. I would like to edit the order and the details at the same time. When I edit the order the ActionResult for the Edit returns the order and the associated line (i'm using EF as well).
public ActionResult Edit(int id)
{
// Get the order with the order lines
var orderWithLines = from o in db.Orders.Include("OrderLines")
where o.ID == id
select o;
// Not sure if this is the best way to do this.
// Need to find a way to cast to "Order" type
List<Order> orderList = orderWithLines.ToList();
Order order = orderList[0];
// Use ViewData rather than passing in the object in the View() method.
ViewData.Model = order;
return View();
}
The order and the lines display with no issue but when I save the page I do not get any of the lines passed back to the controller. Only the order. Here is the View code.
#model OrderTracker.Models.Order
#{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
#using (Html.BeginForm())
{
<fieldset>
<legend>Order</legend>
#Html.HiddenFor(model => model.ID)
#Html.HiddenFor(model => model.UserId)
<div>
#Html.LabelFor(model => model.OrderDate)
</div>
<div>
#Html.EditorFor(model => model.OrderDate)
</div>
<div>
#Html.LabelFor(model => model.Description)
</div>
<div>
#Html.EditorFor(model => model.Description)
</div>
<table>
<tr>
<th>
Description
</th>
<th>
Quantity
</th>
<th>
Weight
</th>
<th>
Price
</th>
<th></th>
</tr>
#foreach (var line in Model.OrderLines)
{
<tr>
<td>
#Html.EditorFor(modelItem => line.Description)
</td>
<td>
#Html.EditorFor(modelItem => line.Quantity)
</td>
<td>
#Html.EditorFor(modelItem => line.Weight)
</td>
<td>
#Html.EditorFor(modelItem => line.Price)
</td>
</tr>
}
</table>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
Can I please get some guidance on the best way to save the line data as well as the order data.
Thanks.
The issue that you are facing is related to the names generated by the ICollection<T> controls. Here is a detailed discussion by Phil Haack and a solution by him (in terms of an #Html extension method; download the sample project from the link given at the end of his blog post). This post targets MVC/MVC2; however it is still applicable with MVC3.
Alternatively if you don't want to follow the hack, you can opt for a EditorTemplate for your OrderLine entity model.
Here are the steps.
1) Create Editor template under (Views ->Shared -> EditorTemplates -> OrderLine.cshtml)
It is important to create a folder named EditorTemplates under Shared, and the template name should be same as the EntityModel for which you want to create the templete; hence the name OrderLine.cshtml)
2) Code for OrderLine.cshtml
#model OrderTracker.Models.OrderLine
#{
Layout = null;
}
<!DOCTYPE html>
#Html.HiddenFor(modelItem => Model.id)
<tr>
<td>
#Html.EditorFor(modelItem => Model.Description)
</td>
<td>
#Html.EditorFor(modelItem => Model.Quantity)
</td>
<td>
#Html.EditorFor(modelItem => Model.Weight)
</td>
<td>
#Html.EditorFor(modelItem => Model.Price)
</td>
</tr>
3) Edit your View with this code (note that I've used EditorFor for OrderLines collection)
#model OrderTracker.Models.Order
#{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
#using (Html.BeginForm())
{
<fieldset>
<legend>Order</legend>
#Html.HiddenFor(model => model.ID)
#Html.HiddenFor(model => model.UserId)
<div>
#Html.LabelFor(model => model.OrderDate)
</div>
<div>
#Html.EditorFor(model => model.OrderDate)
</div>
<div>
#Html.LabelFor(model => model.Description)
</div>
<div>
#Html.EditorFor(model => model.Description)
</div>
<div>
<table>
<tr>
<th>
Description
</th>
<th>
Quantity
</th>
<th>
Weight
</th>
<th>
Price
</th>
</tr>
#Html.EditorFor(model => model.OrderLines)
</table>
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
4) Now on post back you will see the values
Using MVC it should be rather straight forward as the framework is designed to to turn a form into a model.
[HttpGet]
public ActionResult Edit(int id)
{
// (you can probably rewrite this using a lambda
var orderWithLines = from o in db.Orders.Include("OrderLines")
select o;
// Use ViewData rather than passing in the object in the View() method.
ViewData.Model = orderWithLines.FirstOrDefault(x => x.ID = id);
return View();
}
[HttpPost]
public ActionResult Edit(OrderTracker.Models.Order model)
{
if (ModelState.IsValid)
{
// call the service layer / repository / db to persist the object graph
_service.Save(model); // this assumes your view models are the same as your domain
}
}
The issue is with your foreach if you look at the raw html that it produces it will not be generating unique ids for each of the order lines and thus will not be able to bind the model when the form is posted back.
Change the foreach to a for loop and then reference each orderline using the index. This will allow for unique ids to be generated in the form and allow you to bind the to the model when it is posted back.
e.g.
#for (var counter = 0; counter < Model.OrderLines.Count(); counter++)
{
<tr>
<td>
#Html.EditorFor(modelItem => Model.OrderLines[counter].Description)
</td>
<td>
#Html.EditorFor(modelItem => Model.OrderLines[counter].Quantity)
</td>
<td>
#Html.EditorFor(modelItem => Model.OrderLines[counter].Weight)
</td>
<td>
#Html.EditorFor(modelItem => Model.OrderLines[counter].Price)
</td>
</tr>
}
</table>

Categories

Resources