Ajax.BeginForm() not working - c#

Ajax.BeginForm() not working when Html.EditorFor() contains special charactor <
It does not invoke the controller action on submit the form

Have you tried the following:
Index.cshtml
#using (Ajax.BeginForm("PostForm", "Home", new AjaxOptions()))
{
string myFormValue = "";
#Html.EditorFor(x => myFormValue)
<input type="submit" value="Submit"/>
}
HomeController.cs
public class HomeController : Controller
{
public ActionResult PostForm(string myFormValue)
{
return View("Index");
}
When i debug it seems to work:
May you post your code?

Related

FormCollection is not getting passed to the controller

I can post elements from my form if I make a direct reference to the named element in the controller parameters. I am trying to use FormCollection so I do not have to type every element from the form in the post ActionResult parameters.
The HTML form:
#using (Html.BeginForm("legallabels", "Reports", FormMethod.Post, new { id = "reportForm", #class = "report-form col-9" }))
{
<div class="col-12">
<b>Beginning </b><input type="text" class="form-control col-2" id="beginningDatePicker" name="beginningDate" value="#DateTime.Today.Date.ToString("MM/dd/yyyy")" />
</div>
<input type="submit" value="submit">
}
Controller using named parameter (beginningDate):
[HttpPost]
public ActionResult LegalLabels(string beginningDate)
{
return View();
}
When using FormCollection, it does not get passed to the controller:
[HttpPost]
public ActionResult LegalLabels(FormCollection form)
{
return View();
}
Using a breakpoint in the controller, I can see that the form is posting correctly and everything works fine when naming form elements (beginningDate) in the parameters. I've looked at similar samples of code that use FormCollection and they seem to work fine. Why are my FormCollection values not getting passed to the controller?
Tested your code, it works fine. If you see the snippet below you can loop through all posted values and check.
[HttpPost]
public ActionResult LegalLabels(FormCollection form)
{
StringBuilder sb = new StringBuilder();
foreach (var key in form.AllKeys)
{
sb.AppendLine(string.Format("Key: {0}. Value: {1}.<br>", key, form[key]));
}
ViewBag.FormData = sb.ToString();
return View();
}
On the cshtml
<div>
#Html.Raw(ViewBag.FormData)
</div>
After renaming FormCollection to IFormCollection, everything is working properly.

Changing mvc form controller on submit

I recently came upon this question as I have a solution I need to work on.
I have a controller which does some logic, with some method:
public Controller1: MvcController
{
public ActionResult SomeLogic(Model model)
{
return view();
}
public ActionResult SomeLogic2(Model model)
{
return view();
}
}
And I have a second controller which does different logic:
public Controller2: MvcController
{
public ActionResult SomeLogic(Model model)
{
return view();
}
public ActionResult SomeLogic2(Model model)
{
return view();
}
}
Both are working on the same view:
MyView.cshtml
The view contains a begin form that works on submit:
#using(Html.BeginForm("SomeLogic", "Controller1", FormMethod.Post)
and 4 submit buttons:
<input type='submit' formaction='SomeLogic' value='submit' />
<input type='submit' formaction='SomeLogic2' value='submit2' />
<input type='submit' formaction='SomeLogic' value='submit3' />
<input type='submit' formaction='SomeLogic2' value='submit4' />
I know I can control the action to which I am redirecting the submit using the:
formaction attribute.
I there a way to change the controller as well? meaning that:
<input type='submit' formaction='SomeLogic' value='submit3' />
<input type='submit' formaction='SomeLogic2' value='submit4' />
Will submit to controller2 instead of Controller1 which is defined in my begin form.
This will solve my debate whether to create a new controller or use the existing one, which is already full of complex logic.
You need to include controller name in the formaction attribute.
Note that your controller names are not valid, but assuming your have
public FirstController: Controller
{
[HttpPost]
public ActionResult SomeLogic(Model model)
{
return view();
}
}
public SecondController: Controller
{
[HttpPost]
public ActionResult SomeLogic(Model model)
{
return view();
}
}
Then you can post to the correct controller using
// Post to the SomeLogic method of FirstController
<input type="submit" formaction="#Url.Action("SomeLogic", "First")" value="submit" />
// Post to the SomeLogic method of SecondController
<input type="submit" formaction="#Url.Action("SomeLogic", "Second")" value="submit3" />
Just intercept the submit with jQuery
You can add an ID to your form, to be able to select it easily in jQuery
#using(Html.BeginForm("SomeLogic", "Controller1", FormMethod.Post, new { #id = "yourForm" })
Then
$("#yourForm").submit(function(e){
e.preventDefault();
var url1 = '#(Url.Action("SomeLogic1", "SomeController", null, Request.Url.Scheme))';
var url2 = '#(Url.Action("SomeLogic", "SomeController2", null, Request.Url.Scheme))';
//Whatever logic should you do to select which URL you want to POST to
$.ajax({
type: 'POST',
url: url_selected_above,
data: $('#yourForm').serializeArray(),
success: function (xhr, response) {
//...
},
error: function (xhr, response) {
//...
}
});
});
This should work if all the methods expect the same view model.
Alternatively, if you do not want to mess around in the UI, you can do something as such in the action that generates the form.
var controllerName = "SomeController";
var actionName = "Action1";
//do your logic to select whichever controller/action.
viewModel.ControllerName = controllerName;
viewModel.ActionName = actionName;
And in the view that has the form:
#using(Html.BeginForm(#Model.ActionName, #Model.ControllerName, FormMethod.Post)
Again, if all the actions expect the same view model, that should work.

#Html.ValidationSummary works on wrong page

Using asp.net core razor. My current if statement is wrong, but it is the only way to get the error messages to show up. The current if statement is if the ModelState is not valid return to view. On the new view it shows the error messages. However, what I want is if the ModleState is not valid redirect to the Index.cshtml page and show the errors their. When I flipped around my if condition the error messages do not show up in the Index.cshtml page.
Here is my Controller.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using quotingDojo.Models;
namespace quotingDojo.Controllers
{
public class HomeController : Controller
{
// GET: /Home/
[HttpGet]
[Route("")]
public IActionResult Index()
{
return View();
}
[HttpPost]
[Route("quotes")]
public IActionResult Quotes(Home model)
{
if(!ModelState.IsValid)
{
return View();
}
//continue your code to save
return RedirectToAction("Index");
}
}
}
Here is my Index.cshtml
#model quotingDojo.Models.Home
<h1>Welcome to the Quoting Dojo</h1>
#using(Html.BeginForm("Quotes","Home"))
{
<p>#Html.ValidationSummary()</p>
<p>
<label>Your Name</label>
#Html.TextBoxFor(s=>s.Name)
#Html.ValidationMessageFor(s => s.Name)
</p>
<p>
<label>Your Quote</label>
#Html.TextAreaFor(d=>d.Quote)
</p>
<input type="submit" name="submit" value="Add my quote!"/>
}
<form action="quotes" method="get">
<input type="submit" name="submit" value="Skip to quotes!"/>
</form>
Here is my Quotes.cshtml where the error messages currently show up.
<h1>Test</h1>
<p>#Html.ValidationSummary()</p>
Here is my models page
using System.ComponentModel.DataAnnotations;
namespace quotingDojo.Models
{
public class Home
{
[Required(ErrorMessage ="Please enter your name")]
[DataType(DataType.Text)]
[MinLength(3)]
public string Name {get; set;}
[Required]
[MinLength(5)]
public string Quote{get; set;}
}
}
Your issue is here:
return View();
That will return a view named "Quotes" since your action method is named Quotes (this is MVC convention). You also do not pass a model to it so even if the view existed, it will not know of the errors.
Two ways to fix your issue:
1.
You have to pass the model to your Index view so you need to explicitly return the Index view.
if(!ModelState.IsValid)
{
return View("Index", model);
}
2.
I personally prefer this method. Name your first action which serves the original form the same as the one your are posting to and then you can do this (note: you will also need to rename the view):
// GET: /Home/
[HttpGet]
[Route( "" )]
public IActionResult Quotes() {
return View();
}
[HttpPost]
[Route( "quotes" )]
public IActionResult Quotes(Home model) {
if( !ModelState.IsValid ) {
return View(model);
}
//continue your code to save
return RedirectToAction( "Index" );
}
This way both of them return the view named Quotes so you do not have to explicitly mention it.
The standard practice is, If model state is not valid, you return the same view (which user submitted) where you will show the validation error messages. You just need to change your Quotes action method to Index action method.
[HttpPost]
[Route("quotes")]
public IActionResult Index(Home model)
{
if (!ModelState.IsValid)
return View();
// to do :continue saving
}
Make sure to update your form to post to this action.
Not sure why you want to redirect to another page where you want to show the errros.
If you absolutely want to show the error messages in another view which was loaded via RedirectToAction method call (hence a totally new GET call), You need to use TempData to transfer the errors.
public ActionResult Quotes(Home model)
{
if (!ModelState.IsValid)
{
List<string> errors = new List<string>();
foreach (var modelStateVal in ViewData.ModelState.Values)
{
foreach (var error in modelStateVal.Errors)
{
errors.Add(error.ErrorMessage);
}
}
TempData["errors"] = errors;
return RedirectToAction("Index");
}
//continue your code to save
}
And in your index view,
#if (TempData["errors"] != null)
{
var errors = (List<string>) TempData["errors"];
foreach (var error in errors)
{
<span class="alert warning">#error</span>
}
}

Attribute routing

How do you hook up a textbox to a method in MVC5 using attribute routing, with areas?
This is view:
#using (Html.BeginForm())
{
#Html.TextBox("searchpara")
#Html.ActionLink("Search", "SearchMethod", "Home", new { area = "Timetables" }, null)
}
Controller:
[RouteArea("Timetables")]
[RoutePrefix("Home")]
public class HomeController : Controller
{
Method:
[Route("SearchMethod/{searchpara=Test}")]
public ActionResult SearchMethod(string searchpara)
{
It doesn't work. The problem may not be routing?
I believe you want a submit button, and not an action link and you may need to update the form to post to a specific action if it is not the current action.
#using (Html.BeginForm("SearchMethod", "Home", new { area = "Timetables" }))
{
#Html.TextBox("searchpara")
<button type="submit">Search</button>
}

Post back view values to controller MV3

I am new to mvc 3. i am trying to create a view and controller. my scenario is that i have controller which has two actions. while i call first action inside controller i have to load default values to view. inside view i have a buttons to post back values. so while click one of the button inside view, it has to go second action in same controller and has to return back to same view with success or failure message.
My view is like this
#using (Html.BeginForm())
{
<table>
<tr>
<td>
#Html.TextBox("txtTitle")
</td>
<td>
<input type="button" value="Go Somewhere Else" onclick="location.href='#Url.Action("Postback", "Default1")'" />
</td>
</tr>
</table>
}
My Controller,
public class Default1Controller : Controller
{
//
// GET: /Default1/
public ActionResult Index()
{
// has to default load value to text box
return View();
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Postback(FormCollection obj)
{
// has to take value from txt box
object obj1 = Request["txtTitle"];
return View("Index");
}
}
My problem if call Postback action from any other view it works. but inside same view if i click on button the error shows like "http://localhost:14953/Default1/Postback".
What is solution here? i expect to navigate to same controller as well as to other controller inside same form and return to same view.
As reference to this article.....
public class HttpParamActionAttribute : ActionNameSelectorAttribute {
public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo) {
if (actionName.Equals(methodInfo.Name, StringComparison.InvariantCultureIgnoreCase))
return true;
if (!actionName.Equals("Action", StringComparison.InvariantCultureIgnoreCase))
return false;
var request = controllerContext.RequestContext.HttpContext.Request;
return request[methodInfo.Name] != null;
}
}
In view form like this...
#using (Html.BeginForm("Action", "Post")) {
<!— …form fields… -->
<input type="submit" name="SaveDraft" value="Save Draft" />
<input type="submit" name="Publish" value="Publish" />
}
and actions in controller...
public class PostController : Controller {
[HttpParamAction]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult SaveDraft(…) {
//…
}
[HttpParamAction]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Publish(…) {
//…
}
}
You can specify an ActionName to your Postback method like this:
[ActionName("Index")]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Postback(FormCollection obj)...
So F5 repost the same values and calling the URL directly from the address bar returns the View as expected.
There is a constructor for Html.BeginForm Helper method which takes action name and controller name. Use that
public static MvcForm BeginForm(
this HtmlHelper htmlHelper,
string actionName,
string controllerName
)
http://msdn.microsoft.com/en-us/library/dd492590.aspx
So your form should look like this. You dont need the onclick function in your input element.
#using (Html.BeginForm("Postback", "Default1"))
{
//Your elements
<input type="button" value="Go Somewhere Else" />
}
That will render the HTML markup like this
<form action="/Default1/Postback" method="post">
// Your elements
<input type="button" value="Go Somewhere Else" />
</form>
If you want multiple submit button in the same form, It is answered here
I think we can specific action and controller at Html helper.
#using (Html.BeginForm("Postback", "Default1"))
{
<table>
<tr>
<td>
#Html.TextBox("txtTitle")
</td>
<td>
<input type="submit" value="Go Somewhere Else" />
<!-- the input should be submit?-->
</td>
</tr>

Categories

Resources