I have trouble with formcollection.
I have some form in view, and two submit buttons both with unique name="". On debug I get on controller in formcollection all data except "name" of submitted button... I don't know why, 'cos I use this in other forms and there it works good. So I look at the code, but I couldn't find any differencies in using formcollection on not working formcol and working formcol. I tried rename buttons, move them, add referencies which I thought that could help... Nothing. On every submit skip my condition because it give me back only "false" and formcollection my "upload" or "save" button on onclick doesn't contain...
So I would like to ask you for help with this. Can you tell me where could be an error? Thanks to all!
This is in controller:
[HttpPost]
public ActionResult EditUser(EditUserVM model, int id, FormCollection c)
{
//c["upload"] is everytime set to null, 'cos c does't contain it
if (c["upload"] != null)
{
//.... some code
return RedirectToAction("Index", "Home");
}
if (ModelState.IsValid)
{
//.... next code
}
return View("EditUser", model);
}
This is in View:
#model PrukazOnline.ViewModels.EditUserVM
#{
ViewBag.Title = "EditUser";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<script type="text/javascript" src="#Url.Content("~/Scripts/jquery.validate.min.js")"></script>
<script type="text/javascript" src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")"></script>
<script type="text/javascript" src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")"></script>
#using (Html.BeginForm("EditUser", "User", null, FormMethod.Post, new { #class = "form-horizontal", id = "formstep", enctype = "multipart/form-data" }))
{
#*Here is some code - #Html.TextBoxFor(x => x.something) and #Html.ValidationMessageFor(x => x.something) - all of these are in formcollection*#
.
.
.
.
<div>
<input type="submit" value="Nahrát" class="upl" name="upload" id="upload" />
</div>
<div class="submit_buttons">
<input type="submit" name="save" id="save" value="Uložit" />
</div>
}
Issue is in multiple submit inputs in single form. There will only clicked button in FormCollection.
I suppose you try to vary form processing base on clicked button, in this case it's better to use different Actions for each button like this:
View:
<div>
<input type="submit" value="Nahrát" class="upl" name="upload" id="upload" />
</div>
<div class="submit_buttons">
<input type="submit" name="save" id="save" value="Uložit" />
</div>
Controller:
[HttpParamAction]
[HttpPost]
public ActionResult Upload(EditUserVM model)
{
...
}
[HttpParamAction]
[HttpPost]
public ActionResult Save(EditUserVM model)
{
...
}
Related
I have a page which has a partial view (it's a login form). When the submit button is clicked, it calls the controller and logs the person in and refreshes the login form to show that he is logged in.
I now need to update the portion of the screen that shows the login button, or if he is logged in, shows "Hello, Logged In user"
I have a partial view written that shows whether or not the person is logged in, but I don't know how to call it after the success of the first one. I know there is an OnSuccess event, and that seems to be where I would wire that up, but I am not sure how to do this.
#using (Ajax.BeginForm("Login", "Account", new AjaxOptions { InsertionMode = InsertionMode.Replace, UpdateTargetId = "loginSection", }))
{
<div id="loginSection">
...form omitted for clarity.
<input type="submit" value="Log in" />
</div>
}
This is the partial view that needs to be updated after the login.
<ul id="menu">
#if (Request.IsAuthenticated)
{
<text>
Hello, #User.Identity.Name
</text>
}
else
{
<ul>
<a onclick="openLoginWindow()">Login</a>
<a onclick="openRegisterWindow()">Register</a>
</ul>
}
Instead of using Ajax.BeginForm, use normal form and do the form posting with your custom code so that you can controll the success handler as you wish
<div id="login">
#using(Html.Beginform())
{
<input type="text" name="UserName" />
<input type="text" name="Password" />
<input type="submit" id="btnLogin" />
}
</div>
and the script which will listen to the submit button click event and send the form the action method.
$(function(){
$("#btnLogin").click(function(e){
e.preventDefault();
var _this=$(this);
var _form=_this.closest("form");
$.post(_form.attr("action"),_form.serialize(),function(res){
if(res.Status==="authenticated")
{
//Let's hide the login form
$("#login").hide();
$("#yourSecondDiv").html(res.PartialViewContent);
}
else
{
alert("Wrong password");
}
});
});
});
So the javascript code is expecting a JSON structure like below from the controller action
{
"Status":"Authenticated",
"PartialViewContent" : "<p>The markup you want to show</p>"
}
the PartialViewContent will hold the markup you want to show to the user.
public ActionResult Login(string UserName,string Password)
{
//to do : Build the JSON and send it back
}
This answer will tell you how send the markup of a partial view in a JSON property to client.
Here is what worked for me:
Added OnSuccess:
#using (Ajax.BeginForm("Login", "Account", new AjaxOptions {
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "loginSection",
OnSuccess = "successfulLogin"
}))
{... details omitted.
Then added this:
function successfulLogin() {
$('#loginPartial').load('Account/LoginLinksPartial');
which calls in the controller:
public ActionResult LoginLinksPartial()
{
return PartialView("_LoginLinks");
}
I have a partial view like this (simplified):
#model Portal.Models.LoginModel
<div class="login-container k-block">
<section id="login-form" class="">
#using (Html.BeginForm(actionName, controllerName, new { ReturnUrl = ViewBag.ReturnUrl }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset id="login-form-list-items">
<ol>
<li>
#Html.LabelFor(m => m.CardNumber)
#Html.TextBoxFor(m => m.CardNumber, new { #class="k-textbox"})
<div class="k-error-colored">
#Html.ValidationMessageFor(m => m.CardNumber)
</div>
</li>
<li>
#Html.LabelFor(m => m.Pin)
#Html.PasswordFor(m => m.Pin, new { #class="k-textbox"})
<div class="k-error-colored">
#Html.ValidationMessageFor(m => m.Pin)
</div>
</li>
<input id="login-input-submit" class="k-button" type="submit" value="Enter" />
</fieldset>
</div>
And in my login view I call this partial view like:
#model Portal.Models.LoginModel
#Html.Partial("_LoginFormNoRegistration", Model, new ViewDataDictionary { { "actionName", "Login" }, { "controllerName", "Account" } })
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
The problem is that when the login method in the controller adds an error like:
public ActionResult Login(LoginModel model, string returnUrl)
{
//...
// If we got this far, something failed, redisplay form
ModelState.AddModelError("", "The user name or password provided is incorrect.");
return View(model);
}
The message is not show in the validation summary... I don't understand why... What could be the problem? Some javascript library missing?
Update
I also found that the form generated as the novalidate attribute set:
<form action="/" method="post" novalidate="novalidate">
//...
</form>
I don't know why.
I found the problem.
I was passing a new ViewData in the RenderPartial which was overriding the ViewData of the parent view, so the model state was lost, as explained here: Pass Additional ViewData to an ASP.NET MVC 4 Partial View While Propagating ModelState Errors.
Changing the main view to:
#model Portal.Models.LoginModel
#{
ViewData.Add("actionName", "Login");
ViewData.Add("controllerName", "Account");
Html.RenderPartial("_LoginFormNoRegistration", Model, ViewData);
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Did the trick!
Also, if you want to show a general error message for the model in the validationsummary, be sure to add the error with an empty string as key:
ModelState.AddModelError("error", "The user name or password provided is incorrect."); - doesn't work
ModelState.AddModelError("", "The user name or password provided is incorrect."); - works
Remove the true argument in #Html.ValidationSummary()
It could be a few different things off the top of my head. First off you may not be including the required JavaScript. You may not need all of these but i include these in almost all of my layout views.
<script src="#Url.Content("~/Scripts/jquery-1.8.3.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
Also, could you show the code for your partial view? If you are referencing values that are inside a child class in your model the validation can act a little wonky sometimes.
Lastly, this sounds silly but as you did not post the code for your login model make sure you are using the proper data annotations for the values that you want the validation to show up for.
My Controller Action is:
public ActionResult PVInPage()
{
return View();
}
public ActionResult ViewPage2()
{
return PartialView();
}
My Main View:
#using (Html.BeginForm("ViewPage2", "PartialViewInPage"))
{
<input type="submit" value="Call Page Two" />
}
<div id="DisplayPartilView">
#*display partial view *#
</div>
My Partial view Is :
#{
ViewBag.Title = "View Page 2";
}
<div style="width:500px; height:200px; background-color:Gray" >
<h1> This is my Partial view </h1>
</div>
Now I want to do : when i click submit button in my main view then my partial view arise in
My main view inner div with id="DisplayPartilView".
Thanks for response
If you want to load data/html into a page without navigating to a different page you need to use Ajax.
ASP.Net MVC provides a set of helpers to work with Ajax (they are all use jQuery.Ajax under the hood so you can always drop back to one level and write your ajax calls by hand).
But in your case the Ajax.BeginForm provides everything what you need:
So change your main view to:
#using (Ajax.BeginForm("ViewPage2", "PartialViewInPage",
new AjaxOptions() { UpdateTargetId = "DisplayPartilView" }))
{
<input type="submit" value="Call Page Two" />
}
<div id="DisplayPartilView">
#*display partial view *#
</div>
And to make it work you need to reference the following script in your main view or in your layout file after jQuery:
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")" type="text/javascript"></script>
#using (Html.BeginForm("ViewPage2", "PartialViewInPage"))
will refresh page, that's why you need ajax
.serialize() to get data from all inputs and .ajax() to make post request, then set partial:
$('#DisplayPartilView').html(response);
In my project i am doing like this it's below
this is my button which is i click then my partial view load in my div like this
<script type="text/javascript">
$(function () {
$("#btnLode").click(function () {
$("#LodeForm").load("/City/ShowAllState", function () {
alert("Your page loaded Successfully !!!!!!!");
});
});
});
</script>
<div id="LodeForm">
</div>
and this is another solution for this problem
#using (Ajax.BeginForm("SearchCountry", "City",
new AjaxOptions
{
InsertionMode = InsertionMode.Replace,
HttpMethod = "Get",
LoadingElementId = "ajax-loader",
UpdateTargetId = "CountryListID",
}))
{
<input type="submit" value="search Country" data-autocomplete-source="#Url.Action("SearchCountry", "City")" />
}
<div id="CountryListID">
</div>
i think this will help you
First, sorry for my bad english.
I would like when one people click on the button "Page1", the controller return a renderpartial of the "Page1" and the same things for "page2" and "allPage".
My views is:
#{
ViewBag.Title = "Title";
}
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
<h2>Title</h2>
#using (Ajax.BeginForm("NameAction", //controller action name
"NameController", //controller name
new AjaxOptions //ajax options that tell mvc how to perform the replacement
{
UpdateTargetId = "ViewPage", //id of div to update
HttpMethod = "Post" //how to call the controller action
}, new { id = "FormName" }))
{
<input type="submit" id="btn" value="p1" id="p1"/>
<input type="submit" id="btn" value="p2" id="p2"/>
<input type="submit" id="btn" value="AllPage" id="AllPage"/>
<div id="ViewPage">
//render partial view
</div>
}
And my controller is:
public class NameController : Controller
{
[HttpPost]
public ActionResult NameAction(String btn)
{
if (Request.IsAjaxRequest())
if(btn="p1")
return PartialView("p1");
if(btn="2")
return PartialView("p2");
if(btn="3")
return PartialView("p3");
return View();
}
}
Request.isAjaxRequest equals always false and the partialview not update the div but erase all page
Thanks for your helps.
Give your submit buttons a name:
<input type="submit" name="btn" value="page1" id="Page1"/>
<input type="submit" name="btn" value="Page2" id="Page2"/>
<input type="submit" name="btn" value="AllPage" id="AllPage"/>
and then:
[HttpPost]
public ActionResult NameAction(string btn)
{
if (btn == "page1")
{
// the page1 button was clicked
}
else if (btn == "page2")
{
// the page2 button was clicked
}
else if (btn == "AllPage")
{
// the AllPage button was clicked
}
...
}
and if you didn't want to depend on the actual label of the button:
<button type="submit" name="btn" value="p1" id="Page1">Show page 1</button>
<button type="submit" name="btn" value="p2" id="Page2">Show page 2</button>
<button type="submit" name="btn" value="all" id="AllPage">Show all pages</button>
and in the controller you could check against the value.
UPDATE:
Make sure that you have included the jquery.unobtrusive-ajax script to your page so that the Ajax.BeginForm works and sends an AJAX request:
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
How does one obtain the form data after submitting it?
<form target="_self" runat="server">
<p>
<select id="BLAHBLAH2">
<option>2010</option>
<option>2011</option>
<option>2012</option>
<option>2013</option>
</select>
<input type="submit" runat="server" value="Change Year" />
</p>
</form>
This hits the controller's Index method. But, there's nothing in Request.Form. Why?
Second, can I use
<input type="button" instead of type=submit? That is, without introducing ajax via onclick.
Finally, how do I submit to a different method in the controller, e.g. Create?
Try removing those runat server tags. They should not be used in ASP.NET MVC. Also your select doesn't have a name. If an input element doesn't have a name it won't submit anything. Also your option tags must have value attributes which indicates what value will be sent to the server if this options is selected:
<form action="/Home/Create" method="post">
<p>
<select id="BLAHBLAH2" name="BLAHBLAH2">
<option value="2010">2010</option>
<option value="2011">2011</option>
<option value="2012">2012</option>
<option value="2013">2013</option>
</select>
<input type="submit" value="Change Year" />
</p>
</form>
But the correct way to generate forms in ASP.NET MVC is to use HTML helpers. Depending on the view engine you are using the syntax might be different. Here's an example with the Razor view engine:
#model MyViewModel
#using (Html.BeginForm("Create", "Home"))
{
<p>
#Html.DropDownListFor(x => x.SelectedYear, Model.Years)
<input type="submit" value="Change Year" />
</p>
}
Here you have a strongly typed view to some given view model:
public class MyViewModel
{
public string SelectedYear { get; set; }
public IEnumerable<SelectListItem> Years
{
get
{
return Enumerable
.Range(2010, 4)
.Select(x => new SelectListItem
{
Value = x.ToString(),
Text = x.ToString()
});
}
}
}
which is populated by some controller action that will render this view:
public class HomeController: Controller
{
public ActionResult Index()
{
var model = new MyViewModel();
return View(model);
}
[HttpPost]
public ActionResult Create(MyViewModel model)
{
... model.SelectedYear will contain the selected year
}
}
None of your <option> tags have a value:
...
<option value="2010">2010</option>
...
As noted by David, runat="server" is most definitely a WebForms thing, so you can 86 that.
If you want to submit to a different method on your controller you just need to specify the URL for that method.
Easy way using Html.BeginForm:
#using (Html.BeginForm("AnotherAction", "ControllerName")) {
<!-- Your magic form here -->
}
Using Url.Action
<form action="#Url.Action("AnotherAction")" method="POST">
<!-- Your magic form here -->
</form>
You can also use
In Controller
int Value = Convert.ToInt32(Request["BLAHBLAH2"]); //To retrieve this int value
In .cshtml file use
<select id="IDxxx" name="BLAHBLAH2">
//Request[""] will retrieve the VALUE for the html object ,whose "name" you request.