Below Scenario, I think I must see the START text in my form when first loaded.
When I click send data button and submit, I was waiting to see FINISH text in my form.
Buy the START text never changes when I click the button and post the form...
Anybody can tell the problem?
MY CONTROLLER:
namespace MvcApplication1.Controllers
{
public class BuyController : Controller
{
public ActionResult Index(BuyModel model)
{
if (Request.HttpMethod == "GET")
{
model.Message= "START";
return View(model);
}
else
{
BuyModel newModel = new BuyModel();
newModel.Message= "FINISH";
return View(newModel);
}
}
}
}
MY VIEW :
#model MvcApplication1.Models.BuyModel
#using (Html.BeginForm("Index", "Buy", FormMethod.Post))
{
#Html.TextBoxFor(s => s.Message)
<button type="submit" >Send</button>
}
MY MODEL:
public class BuyModel
{
public string Message { get; set; }
}
public class BuyController : Controller
{
public ActionResult Index()
{
BuyModel model = new BuyModel();
model.Message= "START";
return View(model);
}
[HttpPost]
public ActionResult Index(BuyModel model)
{
model = new BuyModel();
model.Message= "FINISH";
ModelState.Clear(); // the fix
return View(model);
}
}
View:
#model MvcApplication1.Models.BuyModel
#using (Html.BeginForm("Index", "Buy"))
{
#Html.TextBoxFor(s => s.Message)
<button type="submit" >Send</button>
}
Your issue is because your original code, that Action Method will only be executed as an HTTP GET request. ASP.NET MVC allows you to specify a post with the [HttpPost] attribute (see above code).
I'm not sure what you are getting at with your POST desired-behavior. It seems like you are just wiping out whatever form values are pushed on the POST. So modify my above code accordingly, but it should give you the general idea.
Edit: it seems to be that the text box is retaining its value after the POST. It's not just with "START", but if you type anything into that text box and hit submit, you'll have a POST with the exact same text in the text box that was there when you submitted the form.
Edit Edit: see the changed code. Call ModelState.Clear() in your POST action method and you'll have the right value reflected.
If you are posting, and not returning a RedirectResult, by default the helpers will use the value from ModelState. You either need to clear ModelState or have a different approach.
The PRG (post redirect get) pattern in MVC is very important. So if its a post, and you aren't redirecting, the helpers assume there is an error that needs to be corrected and the value is pulled from ModelState.
Related
Overview: I am currently attempting to build a create account form. The form is rendered on another razor page. All works correctly, the form displays, sends the form data to a controller, sends data to a class, performs all DB actions, but then upon the completion of the previous items , the program attempts to find a page "CreateAccount.something" when all I want it to do for the time being is to return the initial view upon the return call.
Within said project, a form is displayed via: #RenderPage("~/Views/Home/AccountCreationForm.cshtml")
The form:
#model SuperDuperProject.Models.AccountCreationModel // AccountCreationModel is only a class file containing the necessary variables
...
#using (Html.BeginForm("CreateAccount", "Home", FormMethod.Post))
{
<table cellpadding="0" cellspacing="0">
...
#Html.TextBoxFor(m => m.name)
...
<input type="submit" value="Submit"/>
</table>
}
The Controller file (HomeController.cs):
...
public ActionResult UserLogin() // the page containing the form
{
return View();
}
[HttpPost]
public ActionResult CreateAccount(AccountCreationModel ACM)
{
Console.WriteLine("CreateAccount within HomeController");
Helpers.CreateAccount a = new Helpers.CreateAccount(...);
a.AccountCreationQuery();
return Index(); // ********** Doesn't seem to operate correctly **********
}
Instead of returning Index() or anything placed there, the program attempts to find a CreateAccount view that does not exist.
What am I missing so I can simply return to a desired page, such as Index?
Any assistance would be greatly appreciated.
[HttpPost]
public ActionResult CreateAccount(AccountCreationModel ACM)
{
Console.WriteLine("CreateAccount within HomeController");
Helpers.CreateAccount a = new Helpers.CreateAccount(...);
a.AccountCreationQuery();
return RedirectToAction("Index");
// return Redirect("Home/Index"); alternatively can use Redirect
}
You could consider using RedirectToAction or Redirect.
RedirectToAction returns an HTTP 302 response to the browser, which causes the browser to make a GET request to the specified action. Redirect takes a string type URL parameter and redirects to that specified the URL.
Check out this post for more info:
https://www.codeproject.com/Articles/595024/Controllers-and-Actions-in-ASP-NET-MVC
Try this code
public ActionResult UserLogin() // the page containing the form
{
return View();
}
[HttpPost]
public ActionResult CreateAccount(AccountCreationModel ACM)
{
Console.WriteLine("CreateAccount within HomeController");
Helpers.CreateAccount a = new Helpers.CreateAccount(...);
a.AccountCreationQuery();
return View("Index"); //index is the view here. You can define the view //name which you want to return from this controller action
}
By default controller searches for the view name as the name of the controller action that's why it is attempting to locate the view CreateAccount because controller action name is CreateAccount.
I'm not sure what I am doing wrong. I have never had this problem before or maybe I have, but I've never noticed. I have a page with a partial view. When the page is submitted, the model is checked to see if it has an ID. If it does, it updates the record. If not, it creates a new one. Pretty standard. Once it is done, the model is returned back to the view. The problem I seem to be having is that it isn't updated with any changes to the model. It is just the same model that was posted. Okay so here is some code. I created a brand new project and it still doesn't work.
Also, I used Firebug to look at the raw data coming back and it is still the same model.
Here is the controller:
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Test()
{
return this.View(new Test());
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult TestDetailPost(Test testin)
{
Test test = new Test();
test.Id = "1";
test.Name = "Guy";
return this.PartialView("TestDetail", test);
}
Here is the "Test" view:
#model WebAppTest.Models.Test
#using (Ajax.BeginForm("TestDetailPost", new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "TestDetail" }))
{
<p><input type="submit"/></p>
<div id="TestDetail">
#{ Html.RenderPartial("TestDetail", Model); }
</div>
}
Here is the "Test Detail" view:
#model WebAppTest.Models.Test
<p>#Html.TextBoxFor(a => a.Id)</p>
<p>#Html.TextBoxFor(a => a.Name)</p>
And the model:
public class Test
{
public string Id { get; set; }
public string Name { get; set; }
}
So what I have found is that if I remove the "Test testin" from the TestDetailPost action, it returns the model I created. If I don't, it just returns the same model that was posted. Of course, I am not doing any DB saves or anything, the code above is just for trying to figure out why this is happening.
Here is the details of what I am using:
MVC5
jQuery 1.11.1
jquery.unobtrusive-ajax
I have updated all files to the latest version using NuGet.
Call ModelState.Clear(); in your action method like below:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult TestDetailPost(Test testin)
{
ModelState.Clear();
Test test = new Test();
test.Id = "1";
test.Name = "Guy";
return this.PartialView("TestDetail", test);
}
I have given more details in my answer here. I hope this helps.
Ok so I have an Html.DropDownList and I want to be able to execute a controller method ActionResult output(string test) and send a parameter to it. I have something like this already but I get an Uncaught TypeError: Cannot set property 'action' of null message:
#Html.DropDownList(
"revisions", ViewData["revisions"] as SelectList,
new
{
onchange = "this.form.action = '/Shops/output('test')'; this.form.submit();"
})
How do I go about fixing my code?
If your Action method's parameter name is id,
public ActionResult output(string id)
{
//do something
}
then you may use your form action url like this.(The default routing will take care of rest)
/Shops/output/somestringhere.
If you have a different name, use that as the query string
public ActionResult output(string name)
{
//do something
}
Now use your form action url like
/Shops/output?name=somestringhere
Another suggestion about your code is to avoid Viewdata for rendering the dropdown. Try to use strongly typed view model and it's properties for transfering data to your view. Also try to move your javascript from your view and make it unobutrusive. So that your view stays as clean markup only.
Assuming you want to show a Revision dropdown in a document create view, Add a property to your viewmodel to have the dropdown items.
public class DocumentCreateViewModel
{
//Other properties also here
public List<SelectListItem> Revisions{ set;get;}
public int SelectedRevision { set;get;}
public DocumentCreateViewModel()
{
Revisions=new List<SelectListItem>();
}
}
and in your GET action, fill the dropdown content to the Revisions property.
public ActionResult Create()
{
var vm=new DocumentCreateViewModel();
vm.Revisions=GetRevisionItemsFromSomeWhere();
return View(vm);
}
And in your strongly typed view,
#model DocumentCreateViewModel
#using(Html.Beginform())
{
#Html.DropDownListFor(x => x.SelectedRevision,
new SelectList(Model.Revisions,"Value","Text"), "Select..")
<input type="submit" />
}
Now to handle the form submit on change event of dropdown, add this script.
$(function(){
$("#SelectedRevision").change(function(){
var _this=$(this);
var selectedRevision=_this.val();
$("form#YourFormIDHere")
.attr("action","./Shops/output/"+selectedRevision).submit();
});
});
Instead of hardcoding the url to shops/output, you may use the razor helper method(#Url.Action) to get the proper path.
#Html.DropDownList(
"revisions", ViewData["revisions"] as SelectList,
new
{
onchange = "submitForm();"
})
and your Javacript goes here
function submitForm()
{
var form = document.forms[0];
form = '/Shops/output?test=test';
form.submit();
}
I have a weird need in an ASP.NET MVC 3 application which blocks my current progress. Here is the case:
I have a little search engine for the products and I render this search engine on multiple pages. This SE makes a HTTP POST request to product controller's search action. It fine till here.
Let's assume that I am on home controller's index action (/home/index). I make a search and check if ModelState.IsValid. As a result, it is not valid. So, I should return this back with the entered model (so that user won't lose the values) and model state errors. But when I do that I ended up with different URL (/product/search) as expected.
If I do a redirect, I lose the ModelState and cannot display error messages.
I have different solutions so far and they all look dirty. Any idea?
Edit
Here is a little project which demonstrates this:
This is the ProductController:
public class ProductController : Controller {
[HttpPost]
public ActionResult Search(SearchModel searchModel) {
if (ModelState.IsValid) {
//Do some stuff...
return RedirectToAction("Index", "SearchResult");
}
return View(searchModel);
}
}
This is the SearchModel:
public class SearchModel {
[Required]
public string ProductCategory { get; set; }
[Required]
public string ProductName { get; set; }
}
This is the *_SearchPartial*:
#model MvcApplication20.SearchModel
#using (Html.BeginForm("search", "product"))
{
#Html.EditorForModel()
<input type="submit" value="Search" />
}
And finally this is the Home controller Index action view which renders the *_SearchPartial*:
#{
ViewBag.Title = "Home Page";
}
<h2>#ViewBag.Message</h2>
#Html.Partial("_SearchPartialView")
Here, when I submit the form and if the model state fails, how should I proceed at the Product controller Search action?
Here, when I submit the form and if the model state fails, how should
I proceed at the Product controller Search action?
Normally in this case you should render the _SearchPartialView but not as a partial but as a full view with layout so that the user can fix his errors. No need to stay at Home/Index in this case:
[HttpPost]
public ActionResult Search(SearchModel searchModel) {
if (ModelState.IsValid) {
//Do some stuff...
return RedirectToAction("Index", "SearchResult");
}
// since we are returning a view instead of a partial view,
// the _SearchPartialView template should be displayed with the layout
return View("_SearchPartialView", searchModel);
}
And if you wanted to stay on the same page upon error you could use an AJAX call to perform the search. So you would AJAXify this search form and then in the success callback test the result of the Search action and based on it decide whether to refresh the partial in order to show the error or redirect to the results action using window.location.href:
something along the lines of:
$(document).on('submit', '#searchForm', function() {
$.ajax({
url: this.action,
type: this.method,
data: $(this).serialize(),
success: function(result) {
if (result.redirectTo) {
// no validation errors we can redirect now:
window.location.href = result.redirectTo;
} else {
// there were validation errors, refresh the partial to show them
$('#searchContainer').html(result);
// if you want to enable client side validation
// with jquery unobtrusive validate for this search form
// don't forget to call the .parse method here
// since we are updating the DOM dynamically and we
// need to reattach client side validators to the new elements:
// $.validator.unobtrusive.parse(result);
}
}
});
return false;
});
This obviously assumes that you have now wrapped the partial call in a div with id="searchContainer" and that you provided an id="searchForm" when generating the search form:
<div id="searchContainer">
#Html.Partial("_SearchPartialView")
</div>
and now the search action:
[HttpPost]
public ActionResult Search(SearchModel searchModel) {
if (ModelState.IsValid) {
//Do some stuff...
return Json(new { redirectTo = Url.Action("Index", "SearchResult") });
}
return PartialView("_SearchPartialView", searchModel);
}
As far as I know the ModelState is lost when doing a RedirectToAction, the solution would be to save the modelstate in the TempData one example of this, that I'm using is this:
http://weblogs.asp.net/rashid/archive/2009/04/01/asp-net-mvc-best-practices-part-1.aspx#prg
This is also discussed in various posts for instance MVC Transfer Data Between Views
Question: I have to check the checkbox(which is not part of model) from the action ?
If I select the checkbox and submit to post action, then call the view again the checkbox will be checked fine. But how to check it on first place from non-post action please ? Thanks!
public ActionResult Images(string params)
{
//some code
return View(cp);
}
[HttpPost]
public ActionResult Images(string chbx)
{
//some code
}
Images view:
#using (Html.BeginForm())
{
#Html.CheckBox("chbx")
}
I'm using MVC3 by the way.
do you mean #Html.CheckBox("chbx", true) ?