ASP.NET MVC 5 HttpPost - c#

I have controller:
[HttpGet]
public ActionResult ItemIndex()
{
List<Item> item = RepositoryFactory.Create<IItemRepository>().ItemList();
return View(item);
}
[HttpPost]
public ActionResult ItemIndex(FormCollection formCollection)
{
foreach( string key in formCollection.AllKeys)
{
Response.Write("Key" + key);
Response.Write(formCollection[key]);
}
return View();
}
And view for that:
#model List<Kev.Models.Item>
<div style="font-family:Arial">
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
foreach (var item in Model)
{
#Html.LabelFor(m => item.Start)
#Html.EditorFor(m => item.Start)
#Html.ValidationMessageFor(m => item.Start)
}
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Zapisz" class="btn btn-default" />
</div>
</div>
}
</div>
Repository have DbContext with Item inside.
And what i want to do is fill this textboxes in View, and submit changes to update existing DataBase with this values.
What i did for now is not working code, i cant even make this HttpPost work.
It popup NullReferenceException for >>Model inside #foreach and not sure how to fix that.

Change your foreach to for loop like this:
for(int i=0; i<Model.Count;i++)
{
#Html.LabelFor(m => Model[i].Start)
#Html.EditorFor(m => Model[i].Start)
#Html.ValidationMessageFor(m => Model[i].Start)
}
and change your action parameter form FormCollection to List<Item>:
[HttpPost]
public ActionResult ItemIndex(List<Kev.Models.Item> model)
{
return View();
}

Related

Passing selected string from dropdown to controller

I am displaying a dropdown list from my controller as follows:
public ActionResult Index()
{
var title = new List<String>()
{
"English", "French", "Spanish"
};
List<SelectListItem> languageList = new List<SelectListItem>();
string defaultTitle = "Language";
foreach (var item in title)
{
languageList.Add(new SelectListItem()
{
Text = item,
Value = item,
Selected = (item == defaultTitle ? true : false)
});
}
ViewBag.LanguageList = languageList;
return View();
}
My View is as follows:
#using (Html.BeginForm("GetStatusTrad", "StatusTradController", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Translation</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.Label("Language")
#Html.DropDownList("lang", new SelectList(ViewBag.LanguageList, "Text", "Value"), "Language")
</div>
</div>
<div></div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
}
It displays the dropdown correctly, but when I want to pass the selected value to an action of the controller, I get a 404 error.
My action is :
public ActionResult GetStatusTrad(string language)
{
*some code*
}
Any idea why I can't pass the selected value of the dropdown to the controller?
Your helper should be:
#Html.DropDownList("language", <-- note this
new SelectList(ViewBag.LanguageList, "Text", "Value"), "Language")
It happend becose basically your helper will be rendered to input like this:
<select name="language">
...
</select>
And on form POST your controller will be able to bind your values based on name property of input.
#Html.DropDownList("lang", new SelectList(... generates a <select> with name="lang. You need to change the parameter in the POST method to match
public ActionResult GetStatusTrad(string lang)
As a side note, LanguageList is already IEnumerable<SelectListItem> so using new SelectList() to create another identical one is pointless. I can be just
#Html.DropDownList("lang", (IEnumerable<SelectListItem>)ViewBag.LanguageList, "Language")
You also have a typo in the BeginForm() method. It needs to be
#using (Html.BeginForm("GetStatusTrad", "StatusTrad", FormMethod.Post))
i.e. "StatusTrad", not "StatusTradController" (unless you have really named your controller StatusTradControllerController)
you can use strongly type view to return selected dropdown value.
create simple class like below
public class myModel
{
public string language { get; set; }
....
....
}
Then use this class/model in View
#model yourProject.Models.myModel
<div class="form-group">
<label class="col-lg-2 control-label">Language</label>
<div class="col-lg-5">
#Html.ValidationMessageFor(m => m.language)
#Html.DropDownListFor(m => m.language, new SelectList(ViewBag.LanguageList, "Text", "Value"), "-- Select --", new { #class = "form-control" })
</div>
</div>
Controller method look like below
[HttpPost]
public ActionResult GetStatusTrad(myModel model)
{
*some code*
}

Not sure how to connect an HTML input button to a new ActionResult function

I'm very new to Razor MVC and I can't figure out how to wire an HTML input element click function to an ActionResult. Here is my code:
I took this code from a Login.cshtml file in the project and put it in Index.cshtml:
#model S2GPortal.Models.LoginModel
.
.
.
<section id="featured">
<h2>Use a local account to log in.</h2>
#using (Html.BeginForm(new { ReturnUrl = ViewBag.ReturnUrl })) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Log in Form</legend>
<ol>
<li>
#Html.LabelFor(m => m.UserName)
#Html.TextBoxFor(m => m.UserName)
#Html.ValidationMessageFor(m => m.UserName)
</li>
<li>
#Html.LabelFor(m => m.Password)
#Html.PasswordFor(m => m.Password)
#Html.ValidationMessageFor(m => m.Password)
</li>
<li>
#Html.CheckBoxFor(m => m.RememberMe)
#Html.LabelFor(m => m.RememberMe, new { #class = "checkbox" })
</li>
</ol>
<input type="submit" value="Log in" />
</fieldset>
<p>
#*#Html.ActionLink("Register", "Register")*# if you don't have an account.
</p>
}
</section>
This would, in turn, call a Login ActionResult method on an AccountController controller. When it was in the Login view. Since I've put it in the Index view, the Login method no longer gets called, and I can't figure out how to rewire it to look in the same controller. I'm not sure how MVC knew to call that specific Login ActionResult before. Here is the controller:
public class AccountController : BaseController
{
//
// GET: /Account/Login
[Inject]
public ISystemUserRepository SystemUserRepository { get; set; }
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
if (WebSecurity.IsAuthenticated)
{
string currentUser = WebSecurity.CurrentUserName;
int test = 1;
}
ViewBag.ReturnUrl = returnUrl;
return View();
}
//
// POST: /Account/Login
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginModel model, string returnUrl)
{
if (ModelState.IsValid && WebSecurity.Login(model.UserName, model.Password, persistCookie: model.RememberMe))
{
PortalSession.User = SystemUserRepository.GetByEmail(model.UserName);
return RedirectToLocal(returnUrl);
}
// If we got this far, something failed, redisplay form
ModelState.AddModelError("", "The user name or password provided is incorrect.");
return View(model);
}
So, In summary, How does a view know to look into a specific controller for an ActionResult to call, and how does a line like this: know which ActionResult to call?
Thanks!
you have to use this overload of Html.BeginForm:
#using (Html.BeginForm("Login", "Account", FormMethod.Post, new { ReturnUrl = ViewBag.ReturnUrl }))
{
// your form elements
}
1) First Parameter is ActionName
2) Second Controller Name
3) Third Form Method in your case it will be post as we are posting data
4) and fourth is route values
your final view will be like this:
#model S2GPortal.Models.LoginModel
<section id="featured">
<h2>Use a local account to log in.</h2>
#using (Html.BeginForm("Login", "Account", FormMethod.Post, new { ReturnUrl = ViewBag.ReturnUrl }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Log in Form</legend>
<ol>
<li>
#Html.LabelFor(m => m.UserName)
#Html.TextBoxFor(m => m.UserName)
#Html.ValidationMessageFor(m => m.UserName)
</li>
<li>
#Html.LabelFor(m => m.Password)
#Html.PasswordFor(m => m.Password)
#Html.ValidationMessageFor(m => m.Password)
</li>
<li>
#Html.CheckBoxFor(m => m.RememberMe)
#Html.LabelFor(m => m.RememberMe, new { #class = "checkbox" })
</li>
</ol>
<input type="submit" value="Log in" />
</fieldset>
}
</section>
Now on click of submit button your form will be posted on Login Action of Account Controller and rememeber form will only be posted with <input type="submit"/>, button or link will not work.

Query string param is missed when form validation fail

I have an form with following url:
CreateEntity?officeCodeId=5
When I send form to validate and if validation is fail it returns just CreateEntity url. No officeCodeId=5.
if user click enter on URL or F5 - my site fail - it require missing officecodeId param. I can save it to the session or in the other storage. But I want to have it in the URL
My view:
[HttpGet]
public virtual ActionResult CreateEntity(int? officeCodeId)
{
var model = new CreateViewModel();
FillViewModel(model, officeCodeId);
return View("Create", model);
}
[HttpPost]
protected virtual ActionResult CreateEntity(TEditViewModel model)
{
if (ModelState.IsValid)
{
//Do some model stuff if
}
return View("Create", model);
}
EDIT.
My View:
using (Html.BeginForm("CreateEntity", "Employee", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.HiddenFor(x => x.OfficeCodeId)
<div>
#Html.LabelFor(model => model.FirstName, CommonRes.FirstNameCol)
#Html.TextBoxFor(model => model.FirstName, Model.FirstName)
#Html.ValidationMessageFor(model => model.FirstName)
</div>
<div>
#Html.LabelFor(model => model.LastName, CommonRes.LastNameCol)
#Html.TextBoxFor(model => model.LastName, Model.LastName)
#Html.ValidationMessageFor(model => model.LastName)
</div>
<div> <div class="input-file-area"></div>
<input id="Agreements" type="file" name="Agreements"/>
</div>
}
Edit 2.
Adding:
#using (Html.BeginForm("CreateEntity", "Employee", FormMethod.Post, new { officeCodeId = Model.OfficeCodeId, enctype = "multipart/form-data" }))
Haven`t help.
It produce the following form:
<form action="/PhoneEmployee/CreateEntity" enctype="multipart/form-data" method="post" officecodeid="5">
Solution Is
<form action="#Url.Action("CreateEntity", "Employee")?officecodeid=#Model.OfficeCodeId" enctype="multipart/form-data" method="post">
The problem is your HttpPost action doesn't have any notion of an id parameter. If you want to support a similar URL then make the action signature support that parameter e.g.
[HttpGet]
public ActionResult CreateEntity(int? officeCodeId)
[HttpPost]
public ActionResult CreateEntity(int officeCodeId, EditViewModel model);
Your actions should looks like this:
Actions:
[HttpGet]
public virtual ActionResult CreateEntity(int? officeCodeId)
{
var model = new CreateViewModel();
FillViewModel(model, officeCodeId);
return View("Create", model);
}
[HttpPost]
public virtual ActionResult CreateEntity(ViewModel model)
{
if (model.IsValid) {
// save...
return RedirectToAction("EditEntity", newId!!!);
}
return View("Create", model);
}
Html:
#using (Html.BeginForm()) {
#Html.HiddenFieldFor(m => Model.officeCodeId)
...
}
Your officeId should be in model. And on html form you can store it in hidden field.
Your final answer is excellent and works great, although you can further enhance it to make it more generic by simply including Request.QueryString:
<form action="#Url.Action("CreateEntity", "Employee")?#(Request.QueryString)"
enctype="multipart/form-data" method="POST">
Then use the POST action:
[HttpPost]
protected virtual ActionResult CreateEntity(TEditViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}

Get Textarea value from posted form in MVC3

This is my form
#using (Html.BeginForm("EditPayments", "BookingPathLabelsCms"))
{
if (#Model.DisplayName == "Payment Labels")
{
<textarea id="seeit" name="seeit" rows="5" cols="10"></textarea>
<textarea id="seeitNoSelect" name="seeitNoSelect" rows="5" cols="10"></textarea>
<div class="cmsButtonContainer">
Cancel it
<input type="submit" name="Save" value="Save it"#* onmouseover="copyto();"*# />
</div>
}
}
And this is my controller action
public ActionResult EditPayments(BookingPathLabelsCmsViewModel model)
{
string txtarea = Request.Form["seeit"];
return RedirectToAction("Index");
}
Am not getting the values of textareas here,but values in the breakpoint ,see image.
Your code should looks like:
#using (Html.BeginForm("EditPayments", "BookingPathLabelsCms"))
{
if (#Model.DisplayName == "Payment Labels")
{
#Html.TextBoxFor(m => m.SeeIt)
#Html.TextBoxFor(m => m.SeeItNoSelect)
<div class="cmsButtonContainer">
Cancel it
<input type="submit" name="Save" value="Save it"#* onmouseover="copyto();"*# />
</div>
}
}
Of course, your ViewModel BookingPathLabelsCmsViewModel should have SeeIt and SeeItNoSelect properties. After that, MVC will bind correctly entered data.
First create a class with property.
public class TextAreaProperty
{
public string MyTextAreaValue { get; set; }
}
Use on the view declare like:
#model <project_name>.Models.<Class_name>
In this case:
#model MvcApplication1.Models.TextAreaProperty
Use this textArea Razor
#Html.TextAreaFor(x=> x.MyTextAreaValue)
On method post receiving parameter type TextAreaProperty
[HttpPost]
public ActionResult Index(TextAreaProperty textAreaProperty)
{
return View();
}
You will get the value from textAreProperty.

Adding a variable into the HTML.BeginForm Model

I am having issues retaining the passwordToken between my GET Controller and my View. I see that the token is passed and added to the model correctly within the GET Controller but as soon as the HTML.BeginForm starts in the View the model has a new instance and the previous model with the passwordToken is lost. I need the passwordToken to be retained in order to use WebSecurity.ResetPassword. Any suggestions on how this could be done?
My GET Controller:
[AllowAnonymous]
public ActionResult PasswordReset(string passwordToken)
{
// Token Validation
var usrID = WebSecurity.GetUserIdFromPasswordResetToken(passwordToken);
var usr = _dbManager.GetUserInformation(usrID);
if (usr == null)
{
//The link you are using is not valid anymore
return RedirectToAction("Error", "Account");
}
else
{
var model = new PasswordReset();
model.PasswordResetToken = passwordToken;
return View(model);
}
}
My View:
#model Project.Models.PasswordReset
#{
ViewBag.Title = "Password Reset";
}
<h2>Password Reset</h2>
<div class="form passwordreset-form">
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary()
<div class="input-form">
<div class="inputbox-label">
#Html.LabelFor(m => m.Password)
</div>
<div class="inputbox">
#Html.PasswordFor(m => m.Password)
</div>
<div class="inputbox-label">
#Html.LabelFor(m => m.ConfirmPassword)
</div>
<div class="inputbox">
#Html.PasswordFor(m => m.ConfirmPassword)
</div>
</div>
<div style="float:right;">
<input type="submit" value="Change Password" />
</div>
}
</div>
My POST Controller:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult PasswordReset(PasswordReset model)
{
//Attemp to change password
var passwordChangeConfirmation = WebSecurity.ResetPassword(model.PasswordResetToken, model.Password);
//Password has been changed
if(passwordChangeConfirmation == true)
{
return RedirectToAction("Index", "Home");
}
//Password change has failed
else
{
return RedirectToAction("Error", "Account");
}
}
I ended up adjusting the POST class to make it work.
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult PasswordReset(PasswordReset model, string passwordToken)
{
//Attemp to change password
model.PasswordResetToken = passwordToken;
var passwordChangeConfirmation = WebSecurity.ResetPassword(model.PasswordResetToken, model.Password);
//Password has been changed
if (passwordChangeConfirmation == true)
{
return RedirectToAction("Index", "Home");
}
//Password change has failed
else
{
return RedirectToAction("Error", "Account");
}
}
add it into your form:
#Html.HiddenFor(m => m.PasswordResetToken);
You can use a hidden input on the form for the field (from your model) that you pass it.
#Html.HiddenFor(m => m.PasswordResetToken);
in output
<input type="hidden" name="PasswordResetToken"></input>

Categories