pass a value of the form from view to controller - asp.net-mvc-3

how do i pass the value of the form, which is (i assume) a string of date to the controller...
here is my view:
<script type="text/javascript" language="javascript">
$(function () {
$(".datepicker").datepicker({ onSelect: function (dateText, inst) { $("FORM").submit(); },
altField: ".alternate"
});
});
</script>
#model IEnumerable<CorReservation.Models.Reservation>
#{
ViewBag.Title = "Index";
}
<div class="divRightSide">
<div>
<div class="datepicker">
</div>
<form action="/" title="fff">
<input type="text" class="alternate" readonly="readonly" />
</form>
</div>
// do something eg. foreach (var item in Model)
{ #Html.DisplayFor(modelItem => item.Date)}
here is my controller: i want to pass the date selected from the datepicker to the controller and then the controller would return an Ienumerable of reservations...
DateTime date = System.DateTime.Now;
private ReservationEntities db = new ReservationEntities();
public ViewResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(string dateInput)
{
date = Convert.ToDateTime(dateInput);
var reservations = db.Reservations.Where(r=> r.Date ==date).Include(r => r.Employee).Include(r => r.Room).OrderByDescending(r => r.Date);
return View(reservations);
}

There are 2 ways to do this. Make the form input name attribute match the expected attribute in your controller.
For example:
<input type="text" class="alternate" readonly="readonly" name="dateInput" />
Or if there's going to be a lot of input values, use a Model.

It's automatically done based on the 'name' attribute of the HTML fields you want to submit.
Change your form to
<form action="/" title="fff">
<input name="dateInput" type="text" class="alternate" readonly="readonly" />
</form>
And it should work just like that.
Also, as you are using Razor syntax, you could use the Razor HTML helpers like so
#model IEnumerable<CorReservation.Models.Reservation>
#{
ViewBag.Title = "Index";
}
<div class="divRightSide">
<div>
<div class="datepicker">
</div>
#using(#Html.BeginForm("<your controller name>", "<your action name e.g. Index>"){
Html.TextBox("dateInput", "", new { #readonly="readonly", #class="alternate" })
}
</div>
// do something eg. foreach (var item in Model)
{ #Html.DisplayFor(modelItem => item.Date)}

Related

Handling Razor Dropdowns for auto load values

I have two dropdowns in the view but one relies on the selected value from the other. But how could i load values into the second dropdown after selecting a value from the other? The second dropdown should load values basing on the id selected from the other dropdown.
<div class="form-group">
<label asp-for="BankId" class="control-label col-xs-2"></label>
<div class="col-xs-4">
<select class="form-control" asp-for="BankId" asp-items=#bank>
<option>--- select bank ---</option></select>
</div>
</div>
<div class="form-group">
<label asp-for="BankBranchId" class="control-label col-xs-2"></label>
<div class="col-xs-4">
<select class="form-control" asp-for="BankBranchId" asp-items=#bankbranches>
<option>--- select bank branch ---</option></select>
</div>
</div>
BankBranch should fill values basing on the bank selected from up
Below is example for bank and branches.
you can try out something
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width"/>
<title>Index</title>
</head>
<body>
#using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
#Html.DropDownListFor(m => m.bank, Model.bank, "Please select", new { onchange = "document.forms[0].submit();" })
<br/>
<br/>
#Html.DropDownListFor(m => m.branches, Model.branches, "Please select", new { disabled = "disabled" })
<br/>
<br/>
<input type="submit" value="Submit"/>
}
<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script type="text/javascript">
$(function () {
if ($("#bank option").length > 1) {
$("#bank").removeAttr("disabled");
}
if ($("#branches option").length > 1) {
$("#branches").removeAttr("disabled");
}
if ($("#bank").val() != "" && $("#branches").val() != "") {
var message = "Bank: " + $("#CountryId option:selected").text();
message += "\nbranck: " + $("#StateId option:selected").text();
alert(message);
}
});
</script>
</body>
</html>
public class HomeController : Controller
{
// GET: Home
public ActionResult Index()
{
// populate bank values
foreach (var bankent in entities.bank)
{
model.bank.Add(new SelectListItem { Text = bankent.bank, Value = bankent.id.ToString() });
}
return View(model);
}
[HttpPost]
public ActionResult Index(int? bank)
{
// populate bank values
foreach (var bankent in entities.bank)
{
model.bank.Add(new SelectListItem { Text = bankent.bank, Value = bankent.id.ToString() });
}
if (bank.HasValue)
{
//populate branches based on bank id
foreach (var state in branches)
{
model.branches.Add(new SelectListItem { Text = state.branches, Value = state.StateId.ToString() });
}
}
return View(model);
}
}
for more detail check out Populate one DropDownList based on another DropDownList selected value in ASP.Net MVC

HttpPost not getting triggered

I have a website where I need to redirect the users according to their role. On button click, if the user is admin, redirect to another page; else reload the same page. On button click, the index page is loaded no matter who logs in. On debugging I found out, the [HttpPost] attribute is not triggered at all.
View:
#model namespace.ViewModels.LoginVM
#{
ViewBag.Title = "Login";
}
<h1>User Login</h1>
#using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
<br />
<div style="background-color: skyblue; width: 50%">
<div style="padding-left: 1em">
<div class="display-label" style="font-size: large">
Enter User Info<br />
<br />
</div>
<div>
<div class="editor-label">#Html.LabelFor(model => model.empID)</div>
<div class="editor-field">#Html.TextBoxFor(model => model.empID)
#Html.ValidationMessageFor(model => model.empID)
</div>
<br />
</div>
<br />
<div>
<input id="submit" type="submit" value="Submit" />
</div>
</div>
</div>
<br />
}
Controller:
public class LoginController : Controller
{
[HttpGet]
public ActionResult Login()
{
return View();
}
[HttpPost]
public ActionResult Login(LoginVM model)
{
MySQL msql = new MySQL();
var empID= model.empID
var role = msql.Select("Select `role` from empDB where `eID` = '" + empID + "'");
if(role == "admin")
{
return RedirectToAction("Index","Home");
}
else
{
return View();
}
}
}
Your HttpPost action method name is Login. But your razor view, you used Index!
Update your Html.BeginForm method call to have the correct action method name and controllername values. Then when you click on submit, it will post the form data to /Login/Login
#using (Html.BeginForm("Login", "Login", FormMethod.Post))
{
}

MVC Updating Partial View with Ajax.BeginForm

The Ajax form does update selected div, but instead of just reloading a partial view in that div it inserts the whole page content into that div.
.cshtml file
<fieldset>
<legend>File(s)</legend>
<div id="filesBody">
#Html.Action("Action", "Controller", new {id=Model.Id})
</div>
<br />
#using (Ajax.BeginForm("UploadFile", "Controller", null, new AjaxOptions { UpdateTargetId="filesBody"}, new { enctype = "multipart/form-data", #id = "myForm" }))
{
#Html.HiddenFor(model => model.ComplaintId)
<div>
<label for="File">Add File:</label>
<input type="file" name="FileAttachment" />
<input type="submit" value="Upload" />
#Html.ValidationMessage("FileAttachment")
</div>
}
</fieldset>
Controller
public PartialViewResult GetFilesData(long? Id)
{
Model Model = new Model(Id);
TryUpdateModel(Model);
return PartialView(Model);
}
Partial view
#model Models
<div id="reloadField">
#foreach (var ph in Model.docs)
{
///code
}
</div>
In your partial view set the Layout equal to null.
#model Models
#{
Layout = null;
}
UPDATE
Change your Ajax.BeginForm to call the GetFilesData action.

MVC3 boolean editor template with multiple controls for the same property

I'm using c#, MVC3, Razor and Zurb Foundation 4.
I have a custom editor template for boolean values that will show different UI for different input devices. (visibility is controlled by Foundation's hide-for / show-for css classes)
The problem is that because all of these UI elements are always on the page, only the values in the first one will get bound to the model on post back.
So I either need to find a way of actually removing the HTML for the hidden divs or find a way to use a true value from any of the three elements (they all default to false so whichever is set to true would be the visible one)
This is my Boolean.cshtml:
#model bool
#using System.Web.UI.WebControls
#using Helpers
<div class="hide-for-small">
<div class="hide-for-touch">
<div class="editor-field">
#Html.CheckBoxFor(model => model)
</div>
</div>
</div>
<div class="show-for-small">
<div class="hide-for-touch">
<div class="editor-field">
#{
List<BoolString> ynb = new List<BoolString>();
ynb.Add(new BoolString(false, "No"));
ynb.Add(new BoolString(true, "Yes"));
}
#Html.DropDownListFor(model => model, new SelectList(ynb, "Value", "Description"))
</div>
</div>
</div>
<div class="show-for-touch">
<div class="switch round">
<input id='#ViewData.TemplateInfo.HtmlFieldPrefix + ".Off"' name='#ViewData.TemplateInfo.HtmlFieldPrefix' type='radio' checked />
<label for='#ViewData.TemplateInfo.HtmlFieldPrefix + ".Off"' onclick=''>Off</label>
<input id='#ViewData.TemplateInfo.HtmlFieldPrefix + ".On"' name='#ViewData.TemplateInfo.HtmlFieldPrefix' type='radio' />
<label for='#ViewData.TemplateInfo.HtmlFieldPrefix + ".On"' onclick=''>On</label>
</div>
</div>
Currently the checkbox works fine but the dropdown does not. (I always get false for my model property by the time I get back to the controller).
If I move the dropdown div before the checkbox then the dropdown works but the checkbox does not.
Note that I'm not sure about the touch element yet so it may be wrong anyway. I'm not bothered about getting that working until I have this problem sorted out.
I cooked up a brute force apporach syncronizing each of the inputs using javascript & jquery. Please post if you find a better way
TEST FORM
#using BooleanEditorTemplate.Controllers
#model bool
#{ var modelname = "mmm"; }
#using(Html.BeginForm("Index","Home")){
<div class="hide-for-small">
<div class="hide-for-touch">
<div class="editor-field">
#Html.CheckBox(modelname, Model)
</div>
</div>
</div>
<div class="show-for-small">
<div class="hide-for-touch">
<div class="editor-field">
#{
List<BoolString> ynb = new List<BoolString>();
ynb.Add(new BoolString(false, "No"));
ynb.Add(new BoolString(true, "Yes"));
}
#Html.DropDownList(modelname, new SelectList(ynb, "Value", "Description"))
</div>
</div>
</div>
<div class="show-for-touch">
<div class="switch round">
<input id='#modelname' name='#modelname' type='radio' checked value="on"/>
<label for='#modelname' onclick=''>Off</label>
<input id='#modelname' name='#modelname' type='radio' value="off"/>
<label for='#modelname' onclick=''>On</label>
</div>
</div>
<input type="submit" value="OK"/>
}
TEST SCRIPT
<script src="~/Scripts/jquery-1.7.1.min.js"></script>
<script>
$(function () {
$('[name="#modelname"]').change(
function () {
var id = $(this).attr("id");
var name = $(this).attr("name");
var checked = false;
switch (this.type)
{
case 'checkbox':
checked = $(this).is(":checked");
break;
case 'select-one':
checked = $(this).val().toUpperCase() == 'TRUE';
break;
case 'radio':
checked = $('input[type="radio"][name=' + name + ']:checked').val().toUpperCase() === 'ON';
break;
}
//checkbox
$('input[type="checkbox"][name="' + name + '"]').prop('checked', checked);
//select the select-one
if (checked)
$('select[name="' + name + '"]').val('True');
else
$('select[name="' + name + '"]').val('False');
//select the proper radio
if (checked)
$('input[type="radio"][name='+ name +'][value="on"]').prop("checked", true);
else
$('input[type="radio"][name=' + name + '][value="off"]').prop("checked", true);
});
});
</script>
and my test controler/classes setup
public class HomeController : Controller
{
public ActionResult Index()
{
return View("Index",true);
}
[HttpPost]
public ActionResult Index(Boolean mmm)
{
return null;
}
}
public class BoolString
{
public bool Value { get; set; }
public string Description { get; set; }
public BoolString(bool val, string desc)
{
this.Value = val;
this.Description = desc;
}
}
So this works on my box. I did have to make several modifications as I didn't test this within the editor framework. Undoutably, you'd have to make several more to adapt it back within the scope of your framework.

ASP.NET MVC 3 Model has no information on postback

I have a view with a couple of partial views that I bind to my model. For some reason, when I post, the model is empty, and I am not sure why.
Below is my ViewModel.
public class IndexViewModel
{
public bool AdvancedSearchOption { get; set; }
public bool ForceAdvanced { get; set; }
public bool ForceSimple { get; set; }
public string SimpleSearchCriteria { get; set; }
public string CustomerNumberCriteria { get; set; }
public string AccountNumberCriteria { get; set; }
public string NameCriteria { get; set; }
public string PhoneNumberCriteria { get; set; }
}
Here is my controller. I am filling in all the values of the viewmodel because I wanted to see if the values got to the partial views. They do get there, so it is just on the post that I am having issues.
public class HomeController : Controller
{
private ISecurityRepository SecurityRep;
public HomeController(ISecurityRepository repo)
{
SecurityRep = repo;
}
public ActionResult Index()
{
IndexViewModel temp = new IndexViewModel();
temp.AdvancedSearchOption = SecurityRep.DefaultToAdvancedSearch(User.Identity.Name);
temp.ForceAdvanced = false;
temp.ForceSimple = false;
temp.SimpleSearchCriteria = "Testing";
temp.AccountNumberCriteria = "Acct";
temp.CustomerNumberCriteria = "Cust";
temp.NameCriteria = "Name";
temp.PhoneNumberCriteria = "Phone";
return View(temp);
}
public ActionResult SimpleSearch()
{
IndexViewModel temp = new IndexViewModel();
temp.AdvancedSearchOption = SecurityRep.DefaultToAdvancedSearch(User.Identity.Name);
temp.ForceAdvanced = false;
temp.ForceSimple = true;
temp.SimpleSearchCriteria = "Testing";
temp.AccountNumberCriteria = "Acct";
temp.CustomerNumberCriteria = "Cust";
temp.NameCriteria = "Name";
temp.PhoneNumberCriteria = "Phone";
return View("Index",temp);
}
public ActionResult AdvancedSearch()
{
IndexViewModel temp = new IndexViewModel();
temp.AdvancedSearchOption = SecurityRep.DefaultToAdvancedSearch(User.Identity.Name);
temp.ForceAdvanced = true;
temp.ForceSimple = false;
temp.SimpleSearchCriteria = "Testing";
temp.AccountNumberCriteria= "Acct";
temp.CustomerNumberCriteria= "Cust";
temp.NameCriteria= "Name";
temp.PhoneNumberCriteria = "Phone";
return View("Index", temp);
}
[HttpPost]
public ActionResult Index(IndexViewModel vm, FormCollection formCollection)
{
return View();
}
}
Here is my view
#model TRIOSoftware.Magnum.Models.IndexViewModel
#{
ViewBag.Title = "Search";
}
#if ((#Model.AdvancedSearchOption && #Model.ForceSimple != true) || #Model.ForceAdvanced == true)
{
#Html.Partial("AdvancedSearch")
}
else
{
#Html.Partial("SimpleSearch")
}
Here is my SimpleSearch partial view. I think if I can get this one working, the other will follow the same path. I do the post in the partial and I use jQuery to do it. I am not sure if either of these things could cause me issues or not. I only have all the hidden items in there because I didn't know if not having them was causing my issues.
#model TRIOSoftware.Magnum.Models.IndexViewModel
<script type="text/javascript">
$(document).ready(function () {
$("#DefaultDiv").find("#DefaultAdvanced").click(function () {
$.post("DefaultSimple");
});
$("#SearchSection").find("#SearchButton").click(function () {
$.post("");
});
});
</script>
#using (Html.BeginForm("Index","Home"))
{
#Html.HiddenFor(m => m.ForceAdvanced)
#Html.HiddenFor(m => m.AdvancedSearchOption)
#Html.HiddenFor(m => m.ForceSimple)
#Html.HiddenFor(m => m.AccountNumberCriteria)
#Html.HiddenFor(m => m.CustomerNumberCriteria)
#Html.HiddenFor(m => m.NameCriteria)
#Html.HiddenFor(m => m.PhoneNumberCriteria)
<div id="DefaultDiv" style="float:right">
<a id="DefaultAdvanced" href="#" class="ButtonClass">Default Simple Search</a>
</div>
<div style="clear:both; margin: auto; width: 800px">
<img src="../../Content/images/TRIO_transparent_image.gif"; alt="TRIO Software"; style="margin-left:150px; clear:left"/>
<div style="clear:left; float: left" class="SearchText">
#Html.Label("What's your inquiry?:")
#Html.EditorFor(m => m.SimpleSearchCriteria, new { style = "width: 400px" })
</div>
<div id="SearchSection" style="float: left" class="SearchText">
<img src="../../Content/images/Search.gif"; alt="Search"; style="float:left" />
</div>
<p style="clear:left;margin-left:400px">
#Html.ActionLink("Advanced Search", "AdvancedSearch", null, new { style = "clear:left" })
</p>
</div>
}
Here is the HTML code when viewing the simple search partial view:
<div id="main">
<script type="text/javascript">
$(document).ready(function () {
$("#DefaultDiv").find("#DefaultAdvanced").click(function () {
$.post("DefaultSimple");
});
$("#SearchSection").find("#SearchButton").click(function () {
$.post("");
});
});
</script>
<form method="post" action="/">
<input type="hidden" value="False" name="ForceAdvanced" id="ForceAdvanced" data-val-required="The ForceAdvanced field is required." data-val="true">
<input type="hidden" value="False" name="AdvancedSearchOption" id="AdvancedSearchOption" data-val-required="The AdvancedSearchOption field is required." data-val="true">
<input type="hidden" value="False" name="ForceSimple" id="ForceSimple" data-val-required="The ForceSimple field is required." data-val="true">
<input type="hidden" value="Acct" name="AccountNumberCriteria" id="AccountNumberCriteria">
<input type="hidden" value="Cust" name="CustomerNumberCriteria" id="CustomerNumberCriteria">
<input type="hidden" value="Name" name="NameCriteria" id="NameCriteria">
<input type="hidden" value="Phone" name="PhoneNumberCriteria" id="PhoneNumberCriteria">
<div style="float:right" id="DefaultDiv">
<a class="ButtonClass ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" href="#" id="DefaultAdvanced" role="button"><span class="ui-button-text">Default Simple Search</span></a>
</div>
<div style="clear:both; margin: auto; width: 800px">
<img style="margin-left:150px; clear:left" alt="TRIO Software" ;="" src="../../Content/images/TRIO_transparent_image.gif">
<div class="SearchText" style="clear:left; float: left">
<label for="What_s_your_inquiry_:">What's your inquiry?:</label>
<input type="text" value="Testing" name="SimpleSearchCriteria" id="SimpleSearchCriteria" class="text-box single-line">
</div>
<div class="SearchText" style="float: left" id="SearchSection">
<a class="ButtonClass ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" id="SearchButton" ;="" href="#" role="button"><span class="ui-button-text"><img style="float:left" alt="Search" ;="" src="../../Content/images/Search.gif"></span></a>
</div>
<p style="clear:left;margin-left:400px">
<a style="clear:left" href="/Home/AdvancedSearch">Advanced Search</a>
</p>
</div>
</form>
</div>
How do I fix this problem?
Although you're selecting a partial to render, you're not passing it the model. There's an overloaded version of Html.Partial that takes a second argument that allows you to pass a model to it:
#Html.Partial("ViewName", Model);
So in your case, you'd use this:
#if ((Model.AdvancedSearchOption && Model.ForceSimple != true) || Model.ForceAdvanced == true)
{
#Html.Partial("AdvancedSearch", Model)
}
else
{
#Html.Partial("SimpleSearch", Model)
}
Also notice how I've removed the #s you were prefixing Model with. To better understand why, please see Introduction to ASP.NET Web Programming Using the Razor Syntax and a small reference for this same topic written by Phil Haack here.
I think #john-h hit the nail on the head with his answer. However, you might want to reduce the complexity you've created for yourself.
1) Since both ForceSimple and ForceAdvanced are Boolean, it would be assumed that when ForceAdvanced is true, then it's not "Simple", right? I'm not sure what other logic you have here.
2) Rather than creating two views and "posting" back to get the correct one, why not just use a parameter to set the search type? Or evaluate the security to set which one the user can execute. Here's an example:
Controller Actions:
//id is the search type: true is Advanced
public ActionResult Search(bool id) {
IndexViewModel viewModel = new IndexViewModel {
/* Do whatever logic here */
ForceAdvanced = (id) ? false : true,
AdvancedSearchOption = id
};
return View("search", viewModel);
}
[HttpPost]
public ActionResult Search(IndexViewModel model) {
//model.SimpleSearchCriteria = "Testing";
//model.PhoneNumberCriteria = "Phone";
return View("search", model);
}
Search View:
#using (#Html.BeginForm(new { id = #Model.AdvancedSearchOption })) {
<div style="clear:left; float: left" class="SearchText">
#Html.Label("What's your inquiry?:")
#if (Model.AdvancedSearchOption) {
<div>
#* if you really want, load your partial views here *#
<span>#Html.LabelFor(m => m.NameCriteria)</span>
#Html.EditorFor(m => m.NameCriteria, new { style = "width: 400px" })
<span>#Html.LabelFor(m => m.PhoneNumberCriteria)</span>
#Html.EditorFor(m => m.PhoneNumberCriteria, new { style = "width: 400px" })
</div>
}
else {
#* if you really want, load your partial views here *#
#Html.EditorFor(m => m.SimpleSearchCriteria, new { style = "width: 400px" })
}
</div>
<div>
<input type="submit" value="Search" />
</div>
#Html.HiddenFor(m => m.ForceAdvanced)
#Html.HiddenFor(m => m.AdvancedSearchOption)
#Html.HiddenFor(m => m.ForceSimple)
#Html.HiddenFor(m => m.AccountNumberCriteria)
#Html.HiddenFor(m => m.CustomerNumberCriteria)
#Html.HiddenFor(m => m.NameCriteria)
#Html.HiddenFor(m => m.PhoneNumberCriteria)
}
I had tried explicitly sending in the model to the partials with no luck. I believe that the partial views get the parent model by default if nothing is specified, so all I needed to do was to specify the model type in my partials, and I got the information.
I finally figured it out with a lot of trial and error. My issue was being caused by me trying to use jQuery to do a post. There must be some other things you need to do to update your model doing it this way. Once I changed it out and put an input control on the form for the post, I got all my data back from the parent and partial view in the controller.

Resources