MVC: Passing Value from View to Controller - c#

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" })

Related

Submit form with table - how to pass the selected row number on submit

Here is the Model:
public class TestModel
{
public string Data { get; set; }
public List<string> Datas { get; set; }
}
Here is the view:
#model InventoryWeb.Models.TestModel
#using (Html.BeginForm())
{
#Html.DisplayFor(modelItem => Model.Data)
#Html.HiddenFor(m => m.Data)
<table class="table">
<tr>
<th>
Data
</th>
<th></th>
</tr>
#for (int i = 0; i < Model.Datas.Count; i++)
{
#Html.Hidden("Datas["+ i + "]", Model.Datas[i])
<tr>
<td>
#Html.DisplayFor(modelItem => Model.Datas[i])
</td>
<td>
<input type="submit" value="Submit" formaction="SubmitTest" formmethod="post"/>
</td>
</tr>
}
</table>
}
How to pass the selected row number (the number of row on which user pressed the "Submit" button) to controller? TempData/Viewbag/whatever it is possible to use to pass this info to Controller site when Submitting.
The way you wrote it, it will send all the data back to server for any row.
You can insert a form in each row:
#model InventoryWeb.Models.TestModel
#Html.DisplayFor(modelItem => Model.Data)
<table class="table">
<tr>
<th>
Data
</th>
<th></th>
</tr>
#for (int i = 0; i < Model.Datas.Count; i++)
{
<tr>
<td>
#Html.DisplayFor(modelItem => Model.Datas[i])
</td>
<td>
#using (Html.BeginForm())
{
#Html.Hidden("rowNumber", i)
<input type="submit" value="Submit" formaction="SubmitTest" formmethod="post"/>
}
</td>
</tr>
}
</table>
But I prefer using javascript in this situations.
Edit
With JavaScript:
#using (Html.BeginForm("SubmitTest"))
{
#Html.DisplayFor(modelItem => Model.Data)
#Html.HiddenFor(m => m.Data)
<input type="hidden" id="rowNumber" name="rowNumber" />
<table class="table">
<tr>
<th>
Data
</th>
<th></th>
</tr>
#for (int i = 0; i < Model.Datas.Count; i++)
{
#Html.Hidden("Datas["+ i + "]", Model.Datas[i])
<tr>
<td>
#Html.DisplayFor(modelItem => Model.Datas[i])
</td>
<td>
<input type="button" value="Submit" onclick="SubmitForm(#i, this);"/>
</td>
</tr>
}
</table>
}
<script>
function SubmitForm(i, btn){
$("#rowNumber").val(i);
var form = $(btn).closest("form");
form.submit();
}
</script>
use <button> to replace the <input type="submit" ..>, and set the row number in the value of the <button>
#for (int i = 0; i < Model.Datas.Count; i++)
{
<tr>
<td>
#Html.DisplayFor(modelItem => Model.Datas[i])
</td>
<td>
<button name="rowNumber" value="#i">Submit</button>
</td>
</tr>
}
And if the target post Controller/Action is different the current one, instead of setting formaction and formmethod in every submit button, set it in the Html.BeginForm() like
#using(Html.BeginForm("ActionName", "ControllerName"))
{
...
}

asp.net mvc pass parameters between view and controller

I am a novice in asp.net and i want create simple database application.
I need pass parameters between view and controller to retrieve data from database.
i need only this data which title is "something". I create simple left menu which contains search settings.
This is my view page.
#model IEnumerable<TwojaBiblioteka.Models.Ksiazka>
#{
ViewBag.Title = "Home Page";
}
#Styles.Render("~/Content/css")
<div class="jumbotron">
<script src="~/Scripts/jquery-2.1.4.min.js"></script>
<script src="~/Scripts/jquery.unobtrusive-ajax.min.js"></script>
<div class="container">
<div class="row">
<div class="col-md-2">
<h2>Szukaj</h2>
<div class="textboxes">
<input type="text" name="Tytul" class="form-control" id="Tytul" placeholder="Tytuł..." />
<input type="text" name="txtAutor" class="form-control" id="txtAutor" placeholder="Autor..." />
<input type="text" name="txtISBN" class="form-control" id="txtISBN" placeholder="ISBN..." />
</div>
<center>
#Ajax.ActionLink("Szukaj", "SzukajKsiazki", new AjaxOptions()
{
HttpMethod="GET",
UpdateTargetId= "divKsiazki",
InsertionMode= InsertionMode.Replace
})
</center>
</div>
<div id="divKsiazki"class="col-md-10 ">
</div>
</div>
</div>
</div>
This is view for display data from database:
#model IEnumerable<TwojaBiblioteka.Models.Ksiazka>
<table class="table" style="border:1px solid black;">
<tr>
<th>
#Html.DisplayNameFor(model => model.Tytul)
</th>
<th>
#Html.DisplayNameFor(model => model.Autor)
</th>
<th>
#Html.DisplayNameFor(model => model.ISBN)
</th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Tytul)
</td>
<td>
#Html.DisplayFor(modelItem => item.Autor)
</td>
<td>
#Html.DisplayFor(modelItem => item.ISBN)
</td>
</tr>
}
</table>
And this is my controller:
public PartialViewResult SzukajKsiazki()
{
string tytul="something";
var ksiazkilist = db.Ksiazka.Where(x => x.Tytul == tytul).ToList();
return PartialView("_ListaKsiazek",wypozyczone);
}
So how i can pass data from my textboxes to controller to display only those records which contains textbox text?
Your controller action should accept a parameter. In Asp.Net MVC, it is normal for this to be the model:
public PartialViewResult SzukajKsiazki(IEnumerable<TwojaBiblioteka.Models.Ksiazka> model)
Your view should have all of the editor elements from the model enclosed in a form and you need a submit button:
#using (Html.BeginForm("SzukajKsiazki", "ControllerName", FormMethod.Post)
{
<table class="table" style="border:1px solid black;">
<tr>
<th>
#Html.DisplayNameFor(model => model.Tytul)
</th>
<th>
#Html.DisplayNameFor(model => model.Autor)
</th>
<th>
#Html.DisplayNameFor(model => model.ISBN)
</th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Tytul)
</td>
<td>
#Html.DisplayFor(modelItem => item.Autor)
</td>
<td>
#Html.DisplayFor(modelItem => item.ISBN)
</td>
</tr>
}
</table>
<input type="submit" value="submit">
}

ASP.NET MVC save button loading but not working

I have implemented a save button in my .NET application on the index page. When I click it, it loads, but does not save anything. I am just using the index page for checkboxes. If I uncheck something and save it, it saves, but also unchecks everything else in that row. Nothing happens when I try to check something. Here is the code I'm using:
Index.cshtml
#using (Html.BeginForm("save", "drnos"))
{
<input type="submit" value="Save" />
}
An example of one of my check box fields:
<td>
#Html.EditorFor(modelItem => item.Soft)
#Html.ValidationMessageFor(modelItem => item.Soft)
</td>
drnosController.cs
[HttpPost]
public ActionResult save(Doctor doc)
{
System.Diagnostics.Debug.WriteLine("Save Called");
db.Entry(doc).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
Here is the whole HTML file:
#model PagedList.IPagedList<drnosv6.Models.Doctor>
#using PagedList.Mvc;
<link href="~/Content/PagedList.css" rel="stylesheet" type="text/css" />
#{
ViewBag.Title = "Index";
}
<h2>Doctors</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
#using (Html.BeginForm()) //insert the search bar
{
<p>
Find by First Name, Last Name, or RVH ID: #Html.TextBox("SearchString")
<input type="submit" value="Search" />
</p>
}
#using (Html.BeginForm("save", "drnos"))
{
<input type="submit" value="Save" />
}
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
$('tr:even').addClass('alt-row-class');
});
</script>
<p>
</p>
<p>Click on a column header to sort by that column</p>
<table>
<tr>
<th>
#Html.ActionLink("RVH ID", "Index", new { sortOrder = ViewBag.IDSortParm })
</th>
<th>
#Html.ActionLink("Last Name", "Index", new { sortOrder = ViewBag.LastSortParm })
</th>
<th>
#Html.ActionLink("First Name", "Index", new { sortOrder = ViewBag.FirstSortParm })
</th>
<th>
Middle Initial
</th>
<th>
Degree
</th>
<th>
Group
</th>
<th>
Adm Priv
</th>
<th>
#Html.ActionLink("QCPR", "Index", new { sortOrder = ViewBag.QCPRSortParm })
</th>
<th>
#Html.ActionLink("Keane", "Index", new { sortOrder = ViewBag.KeaneSortParm })
</th>
<th>
#Html.ActionLink("Orsos", "Index", new { sortOrder = ViewBag.OrsosSortParm })
</th>
<th>
#Html.ActionLink("Soft", "Index", new { sortOrder = ViewBag.SoftSortParm })
</th>
<th>
#Html.ActionLink("3M", "Index", new { sortOrder = ViewBag.threeMSortParm })
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
using (Html.BeginForm("Save", "Doctor", FormMethod.Post))
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.RVH_ID_)
</td>
<td>
#Html.DisplayFor(modelItem => item.Last_Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.First_Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Middle_Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Degree1)
</td>
<td>
#Html.DisplayFor(modelItem => item.Group)
</td>
<td>
#Html.DisplayFor(modelItem => item.AdmPriv)
</td>
<td>
#Html.DisplayFor(modelItem => item.QCPR)
</td>
<td>
#Html.EditorFor(modelItem => item.Keane)
#Html.ValidationMessageFor(modelItem => item.Keane)
</td>
<td>
#Html.EditorFor(modelItem => item.Orsos)
#Html.ValidationMessageFor(modelItem => item.Orsos)
</td>
<td>
#Html.EditorFor(modelItem => item.Soft)
#Html.ValidationMessageFor(modelItem => item.Soft)
</td>
<td>
#Html.DisplayFor(modelItem => item.C3M)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.RVH_ID_ })
#Html.ActionLink("Details", "Details", new { id = item.RVH_ID_ })
</td>
</tr>
}
}
</table>
<p>
<input type="submit" value="Save" />
</p>
<br />
Page #(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of #Model.PageCount
#Html.PagedListPager(Model, page => Url.Action("Index", new { page, sortOrder = ViewBag.CurrentSort, currentFilter = ViewBag.CurrentFilter }))
Your BeginForm or ActionLink has to point to ActionResult Edit.
When a form is submitted, only the inputs declared within that form get submitted. You only have the submit button in your form, so there are no other fields to fill out your Doctor structure. You need to have your save button on the same form as all your other fields.

ListBoxFor within IEnumerable model

My model -
...
public string[] _SelectedCountries { get; set; }
and my view -
#using System.Collections.Concurrent
#using Example.Models
#model IEnumerable<Example.Models.vw_SpecialQuestionDefinition>
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#using (Html.BeginForm("Create", "SpecialQuestionDefinition", FormMethod.Post))
{
#Html.AntiForgeryToken()
#Scripts.Render("~/Scripts/SpecialQuestions/Index.js")
<div class="row">
<div class="col-md-4">
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">Host Country</h4>
</div>
<div class="panel-body">
#*#Html.ListBoxFor("countries", null, new { #class = "sqQuestions" })*#
#Html.ListBoxFor(model => model._SelectedCountries,
new MultiSelectList((List<SelectListItem>)ViewData["countries"], "Value", "Text"),
new { style = "display:block;", #class = "sqQuestions" })
</div>
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-5 col-md-12">
<input type="submit" value="Configure" class="btn btn-default"/>
</div>
</div>
<input type="hidden" name="specialQuestionsId" id="specialQuestionsId" value="-1" />
<input type="hidden" name="answerTypesId" id="answerTypesId" value="-1" />
<input type="hidden" name="hostCountrysId" id="hostCountrysId" value="-1" />
<input type="hidden" name="nationalitysId" id="nationalitysId" value="-1" />
<input type="hidden" name="scopeTypesId" id="scopeTypesId" value="-1" />
}
<h4>Special Question Definition</h4>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Question)
</th>
<th>
#Html.DisplayNameFor(model => model.AnswerType)
</th>
<th>
#Html.DisplayNameFor(model => model.LookupTable)
</th>
<th>
#Html.DisplayNameFor(model => model.CountryName)
</th>
<th>
#Html.DisplayNameFor(model => model.NationalityName)
</th>
<th>
#Html.DisplayNameFor(model => model.ScopeType)
</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Question)
</td>
<td>
#Html.DisplayFor(modelItem => item.AnswerType)
</td>
<td>
#Html.DisplayFor(modelItem => item.LookupTable)
</td>
<td>
#Html.DisplayFor(modelItem => item.CountryName)
</td>
<td>
#Html.DisplayFor(modelItem => item.NationalityName)
</td>
<td>
#Html.DisplayFor(modelItem => item.ScopeType)
</td>
</tr>
}
</table>
and within my controller -
List<SelectListItem> listCountriesSelectListItems = new List<SelectListItem>();
listSpecialQuestionsSelectListItems.Add(new SelectListItem() { Text = "All", Value = "-1" });
foreach (Country co in db.Countries.OrderBy(c => c.CountryName))
{
SelectListItem selectList = new SelectListItem()
{
Text = co.CountryName,
Value = co.CountryId.ToString()
};
listCountriesSelectListItems.Add(selectList);
}
ViewBag.countries = listCountriesSelectListItems;
so when I run the application, I get this error for my ListBoxFor -
'System.Collections.Generic.IEnumerable<Example.Models.vw_SpecialQuestionDefinition>' does not contain a definition for '_SelectedCountries' and no extension method '_SelectedCountries' accepting a first argument of type 'System.Collections.Generic.IEnumerable<Example.Models.vw_SpecialQuestionDefinition>' could be found (are you missing a using directive or an assembly reference?)
And I believe I understand why I get that error. Because I am trying to treat the model within the view as a single object, when in actuality it's of type IEnumerable<Example.Models.vw_SpecialQuestionDefinition>.
How do I get to _SelectedCountries from my model then?
Also, I use an IEnumerable model to populate a table beneath the list box. This list box is outside of the table and has no reason to be inside of it.
EDIT - POSTED entire view.
I am trying to treat the model within the view as a single object,
when in actuality it's of type
IEnumerable.
Your assumption is correct.
How do I get to _SelectedCountries from my model then?
You need a new model and add IEnumerable inside it.
public class SomeViewModel
{
public IEnumerable<vw_SpecialQuestionDefinition>
SpecialQuestionDefinitions { get; set; }
public string[] _SelectedCountries { get; set; }
}
Then foreach will finally like this -
#foreach (var item in Model.SpecialQuestionDefinitions)

Displaying a PartialView with updated data

C#, MVC4
I have a PartialView created for a popup data entry on a form. This is a snippet from the main form.
<input type="button" id="btnAddGroup" value="Add Group" />
<p>
<input type="submit" value="Save" />
</p>
</div>
</fieldset> }
I discovered quickly that I needed to have the line:
#Html.Partial("_Groups")
Outside the primary view so the form submit button in the partial view would accept and process.
My controller processes and sends back the data using:
return PartialView(NewModel);
I can run the debugger and see that the data is getting passed back to the PartialView but since the view sits outside the original form, it's not displaying.
My PartialView is as follows:
#model OMD.ViewModels.SearchedUser
#if (Model.AddGroups != null)
{
<h2>Groups to be Added</h2>
<table id="AddGroupList">
<thead>
<tr>
<th>
Name
</th>
<th>
Until
</th>
<th>
Action
</th>
</tr>
</thead>
<tbody>
#foreach (var Group in Model.AddGroups)
{
<tr>
<td>
#Html.DisplayFor(model=> Group.GroupName)
</td>
<td>
#Html.DisplayFor(model=> Group.dtAddedTo)
</td>
<td>
#Html.DisplayFor(model=> Group.bAddOrRemove)
</td>
<td>
#if (AuthCheck.CheckUser(new HttpContextWrapper(HttpContext.Current), oRoles.StaffChangeRequest) ||
AuthCheck.CheckUser(new HttpContextWrapper(HttpContext.Current), oRoles.StudentChangeRequest))
{
<span>#Html.ActionLink("Remove", "RemoveGroup", new { id = Group.ID })</span>
}
</td>
</tr>
}
</tbody>
</table>
}
<div id="dlgAddGroup" title="Add Group" style="display: none">
#using (Ajax.BeginForm("_Groups",new AjaxOptions { UpdateTargetId ="ID",OnSuccess="onSuccess"}))
{
#Html.DropDownListFor(model => model.AllGroups,new SelectList(Model.AllGroups, "ID","GroupName"), "Select Group to Add")
#Html.ValidationMessageFor(model => model.AllGroups)
<div class="editor-label">
#Html.CheckBox("cbxMakeGroupPermanent", true) Permanent
</div>
<div class="editor-label" id ="dlgUntil1">
Group Add Until:
</div>
<div class="editor-field" id="dlgUntil2">
#Html.TextBox("tbAddUntil",null,new { maxlength = 30, style = "width: 100px" })
<span style='padding:5px'><img id='calImageGroup' alt="img" src='~/Images/calendar.gif'></span>
</div>
<button class="btn btn-inverse" type="submit">add</button>
}
I can see the table at the top display the information posted back to it but it doesn't show on the screen...
How can I get this data/table to display?

Categories

Resources