MVC Razor get option value from select with FormCollection - html

My view has a Select with elements(options) from my ViewModel.
#using (Html.BeginForm("NewUser", "Admin"))
{
<select multiple="" id="inputRole" class="form-control" size="6" name="inputRole">
#foreach (var item in Model.roller)
{
<option>#item.Name</option>
}
</select>
}
How can i get the selected value in my Controller?
[HttpPost]
public ActionResult NewUser(FormCollection formCollection)
{
String roleValue1 = formCollection.Get("inputRole");
}
This gives me a null value.

Try this to get the value of control in the formcollection
formCollection["inputRole"]
Your code becomes
[HttpPost]
public ActionResult NewUser(FormCollection formCollection)
{
String roleValue1 = formCollection["inputRole"];
}

You can simply accesss your form field by its name in that way
String role = formCollection["inputRole"];

Related

How to pass an array from main view to partial view in asp.net mvc 5

I've a main view that contains an array received from the corresponding Action and it also contains a partial view reference below
Create.cshtml :
#model HrAndPayrollSystem.Models.EmployeeMasterA
#using (Html.BeginForm())
{
ViewData["fs_lbls"] = ViewBag.FS_lbls as string[];
#Html.Partial("~/Views/EmployeeMasterA/FinalSettlementTAB.cshtml", Model)
}
and the referenced partial view above is defined below
FinalSettlementTAB.cshtml :
#model HrAndPayrollSystem.Models.EmployeeMasterA
#Html.DropDownList("DeptId", null, "Department")
/* Print "ViewData["fs_lbls"]" array defined in the Main View `Create.cshtml` here */
I've an array defined in the Create.cshtml, now, I want to pass it into the partial view HR_EmployeeFinalSettlementTAB.cshtml and print it, What is the proper way to to this?
What I've tried :
I changed the #Html.Partial() line into below :
#Html.Partial("~/Views/EmployeeMasterA/FinalSettlementTAB.cshtml", null, new ViewDataDictionary { { "fs_lbls", ViewData["fs_lbls"] } })
and modified the FinalSettlementTAB.cshtml file as below :
#model HrAndPayrollSystem.Models.EmployeeMasterA
#Html.DropDownList("DeptId", null, "Department")
#foreach (var i in ViewData["fs_lbls"] as string[])
{
#i
}
But it throws an exception InvalidOperationException at line #Html.DropDownList("DeptId", null, "Department") by saying :
There is no ViewData item of type 'IEnumerable' that has the key 'DeptId'.
It throws the above exception whenever I try to pass the array data to the partial view using ViewDataDictionary, otherwise, it is working fine, when I'm not.
How do I get rid of the above exception and properly pass array data from main view to the partial view?
I suggest that you add a new property to EmployeeMasterA to store the labels, so that you do not need to use ViewData at all.
public class EmployeeMasterA
{
public string[] fs_lbls { get; set; }
public string SelectedLabel { get; set; }
public List<SelectListItem> Labels
{
get
{
if (this.fs_lbls == null)
{
return Enumerable.Empty<SelectListItem>().ToList();
}
return (from label in fs_lbls
select new SelectListItem
{
Text = label,
Value = label
}).ToList();
}
}
}
Create.cshtml
#model WebApplication1.Controllers.EmployeeMasterA
#using (Html.BeginForm())
{
#Html.Partial("FinalSettlementTAB", Model)
<input type="submit" value="Save"/>
}
FinalSettlementTAB.cshtml
#model WebApplication1.Controllers.EmployeeMasterA
#Html.DropDownList("SelectedLabel", Model.Labels)
Controller
public ActionResult Create()
{
var viewModel = new EmployeeMasterA();
viewModel.fs_lbls = new[] {"Label1", "label 2"};
return View(viewModel);
}
[HttpPost]
public ActionResult Create(EmployeeMasterA viewModel)
{
return View();
}
You can set the content of fs_lbls in the controller action method, before returning the Create view. When you post the form, the SelectedLabel property will contain the selected item from the dropdown list. Obviously you will need to change the property names to suite your needs, but hopefully this will give you an idea.

Post html select to MVC Controller. Finding a better way

I'm just looking for a better way to do the following :
I've got an html select :
<form method="post" action="/Account/ChangeUserRole">
<select name="Val" onchange="this.form.submit();" class="span2">
#foreach (var r in ViewBag.UserRoles)
{
#if (u.UserRole.ID == r.ID)
{
<option selected="selected" value="#u.ID/#r.ID">#r.Name</option>
}
else
{
<option value="#u.ID/#r.ID">#r.Name</option> // <-- better way?
}
}
</select>
</form>
I'm posting it as "userid/roleid" and on the controller side doing a string.Split on / to split u.ID and r.ID
I would like to know if it's possible to post it so my controller get's them in this way :
[HttpPost]
public IActionResult ChangeUserRole(int UserID, int RoleID)
Instead of this witchcraft:
[HttpPost]
public IActionResult ChangeUserRole(string Val)
{
char[] splitChar = new char[] { '/' };
string[] s = Val.Split(splitChar);
int UserID = Convert.ToInt32(s[0]);
int RoleID = Convert.ToInt32(s[1]);
}
Sorry for the long post. Hope my question makes sense.
I'm not such a big fan of html helpers.
Side note:
I'm using MVC 6, ASP 5 - RC1
Appreciate the help
Cheers!
The best solution is to use the TagHelpers to build your dropdown. Let's start by creating a view model specific to this view.
public class UserRoleEditVm
{
public List<SelectListItem> Roles { set; get; }
public int RoleId { set; get; }
public int UserId { set; get; }
}
In your get action, create an object of this, load the property values and send it to the view.
public IActionResult Create()
{
// User Id and Role list is hard coded for demo. You may replace it with real data.
var v = new UserRoleEditVm {UserId = 45};
v.Roles = new List<SelectListItem>
{
new SelectListItem {Value = "1", Text = "Admin"},
new SelectListItem {Value = "2", Text = "Editor"},
new SelectListItem {Value = "3", Text = "Reader"}
};
return View(v);
}
And in your view, which is strongly typed to our view model, we will like Tag helpers to for creating the HTML markup.
#model UserRoleEditVm
<form asp-action="ChangeUserRole" asp-controller="Account">
<select asp-for="RoleId" asp-items="#Model.Roles">
<option>Please select one role</option>
</select>
<input type="hidden"asp-for="UserId"/>
<input type="submit"/>
</form>
And in your HttpPost action method, you can use an object of our view model as the parameter and the Model binder will map the posted form values to property values of that object.
[HttpPost]
public ActionResult ChangeUserRole(UserRoleEditVm model)
{
var userId = model.UserId;
var roleId = model.RoleId;
// to do : Do something with the above 2 values
// to do :Save and redirect (PRG pattern)
// return RedirectToAction("Success");
}

Pass string to action method overload

So what I want to do is take a string from a textarea and pass it to an action method overload (string paramJSON).
Action method:
public ActionResult SendMail(string templateName, string receiver, string paramJSON)
{
var paramDictionary = JsonConvert.DeserializeObject<Dictionary<string, string>>(paramJSON);
new SendMailClient().Send(templateName, receiver, paramDictionary);
if(Request.IsAjaxRequest())
{
return RedirectToAction("SendPartial", "TestMail");
}
return View();
}
Textarea:
#Html.TextAreaFor(a => a.TestParametrar, new { id = "paramTxt" })
Your html helper
#Html.TextAreaFor(a => a.TestParametrar, new { id = "paramTxt" })
generates a textarea with name="TestParametrar". When you submit a form, it sends back the values of each controls name and value attributes in this case TestParametrar: 'The text you entered' You method needs to include a parameter with the same name, for example
public ActionResult SendMail(string TestParametrar, ....)
and the value of the parameter will be the text entered in the form control.
However, since you view is based on a model, then it is better to just post back to the model and all properties will be bound
public ActionResult SendMail(YourModel model)
which has the added benefit of validating your properties. For example, if property TestParametrar has the [Required] attribute, then if the user does not enter a value, ModelSTate will be invalid and the view can be returned for correction.
#using (Html.BeginForm("SendMail2"))
{
#Html.TextAreaFor(a => a.TestParametrar, new { id = "paramTxt" })
<input type="submit" value="Send Message" />
}
And:
public ActionResult SendMail2(string TestParametrar)
{
return SendMail("myTemplate", "hello#world.com", TestParametrar);
}

ASP.NET Cross session list

I'm attempting to make a simple page that will compare multiple form submissions.
I have a html page with a form, and a for-loop that generates a div for each item in a list of form submissions. The list is passed from the controller. I am trying to maintain the list in the controller rather than rely on a database.
When I try to resubmit the form, which should add another object to the list, the list re initializes.
In debugging, I see that the list is empty when the form gets submitted. I'm unsure as to the correct terminology, but it seems that the list is emptied whenever the view is rendered. Is there a way to maintain list contents?
I know there are better ways to do this, and welcome any advice. I'm still learning, so pleas go easy.
Thanks!
This is the simplified controller.
namespace MvcApplication2.Controllers
{
public class HomeController : Controller
{
List<paymentPlan> plansList = new List<paymentPlan>();
public ActionResult Index()
{
return View(plansList);
}
[HttpPost]
public ActionResult Index(FormCollection collection)
{
paymentPlan Project = new paymentPlan();
Project.customerName = Convert.ToString(collection["customerName"]);
plansList.Add(Project);
return View(plansList);
}
}
}
This is my simplified view.
#model List<MvcApplication2.Models.paymentPlan>
#using (Html.BeginForm("index", "home", FormMethod.Post, new { Id = "signupForm" }))
{
<label for="customerName">Customer Name:</label>
<input type="text" name="customerName" class="form-control required" />
#Html.ValidationSummary(true)
<input type="submit" value="Calculate" class="btn btn-primary" />
}
#{
bool isEmpty = !Model.Any();
if (!isEmpty)
{
foreach (var i in Model)
{
<div>
Name: #i.customerName
</div>
}
}
}
This is my simplified model.
namespace MvcApplication2.Models
{
public class paymentPlan
{
public string customerName { get; set; }
}
}
I think that's a question of controller and asp.Net MVC lifecycle !
A controller lifetime is the same as the request, for each request a new controller is created and once the work is done it's disposed!
So try to remove this List<paymentPlan> plansList = new List<paymentPlan>(); and work with TempData[] or ViewData[] or Session[] like this :
Controller
public class HomeController : Controller
{
public ActionResult Index()
{
Session["plansList"] = ((List<paymentPlan>)Session["plansList"])!=null? (List<paymentPlan>)Session["plansList"] : new List<paymentPlan>();
return View((List<paymentPlan>)Session["plansList"]);
}
[HttpPost]
public ActionResult Index(FormCollection collection)
{
paymentPlan Project = new paymentPlan();
Project.customerName = Convert.ToString(collection["customerName"]);
((List<paymentPlan>)Session["plansList"]).Add(Project);
return View(plansList);
}
}
check this : http://www.asp.net/mvc/overview/getting-started/lifecycle-of-an-aspnet-mvc-5-application

better way to fill dropdown list in mvc

I have tried to create dropdown list with tag
<select name="manufacturer" class="form-control">
<option>#null</option>
#foreach (var item in Model) {
<option>#item.Manufacturer</option>
}
</select><br>
but here is a problem: It doesn't populate all available manufacturers and only shows items, from current page. Example: http://i.imgur.com/na0x5eQ.png
that's because it uses the model passed from controller which doesn't always contain every item from the database. (because of pagination or after search)
Here is full sidebar code in partial view
#model IPagedList<Products>
#using PagedList
#using PagedList.Mvc
<div id="filter" class="left">
#using (Html.BeginForm("Filter", "SearchFilter")) {
<div>
<b>Manufacturer:</b> <br>
<select name="manufacturer" class="form-control">
<option>#null</option>
#foreach (var item in Model) {
<option>#item.Manufacturer</option>
}
</select><br>
<b>Name:</b> <br>#Html.TextBox("name", null)<br>
<b>Price From:</b> <br>#Html.TextBox("min", null)<br>
<b>To:</b> <br>#Html.TextBox("max", null)<br>
<button type="submit" value="search"><b>Search</b></button>
</div>
}
</div>
So what are the ways to fix this?
Since you know why it's occurring
that's because it uses the model passed from controller which doesn't always contain every item from the database. (because of pagination or after search)
then why not fix it right there. Maybe you need a separate validation table for manufacturers (if you don't already have one).
Model:
public class ProductsModel
{
public IPagedList<Products> CurrentProducts {get; set;}
public int ManufacturerId {get; set;}
public int MinPrice{get; set;}
public int MaxPrice{get; set;}
}
Controller action:
[HttpGet]
public ViewResult CurrentProducts()
{
ProductsModel model = new ProductsModel();
model.CurrentProducts = _repository.Product;
ViewBag.ManufacturerId = from p in _repository.Product select p.Manufacturer;
return View(model);
}
[HttpPost]
public ViewResult CurrentProducts(ProductsModel model)
{
if(ModelState.IsValid)
{
model.CurrentProducts = _repository.Product.Where(t=>t.ManufacturerId == model.ManufacturerId);
ViewBag.ManufacturerId = from p in _repository.Product select p.Manufacturer;
}
return View(model);
}
And in the view, create a dropdown list like this:
#model MyNameSpace.ProductsModel
#Html.DropDownListFor(model=> model.ManufacturerId, string.Empty);