I'm using FluentValidation with FormHelper in order to validate my form using ajax.
My form has 2 submit buttons:
Default one that should run validation (Save method in controller has [FormValidator] annotation)
Second one (calls another controlers' method) should have validation disabled (Save method in controller has no validation annotation)
At this moment both buttons do POST call to Save method so validation run in both cases. If I remove FormHelper validation tags, client calls correct methods but there is no validation off course.
What should I do in order to enable validation only for one button?
View:
<form id="myFrom" asp-controller="MyController" asp-action="Save" method="post" asp-formhelper="true">
<label asp-for="MyField" class="form-label">My field: </label>
<input asp-for="MyField" class="form-control"/>
<span asp-validation-for="MyField" class="text-danger"></span>
<input type="submit" value="POST with validation">
<input type="submit" asp-controller="MyController" asp-action="AnotherAction" value="Post without validation">
</form>
Controller:
public class MyController
{
[HttpPost, FormValidator]
public async Task<IActionResult> Save(MyViewModel vm)
{
//do sth
}
[HttpPost]
public async Task<IActionResult> AnotherAction(MyViewModel vm)
{
//do another actions
}
}
Related
Problem: Hi there, so in a view where a product is displayed I have a button to call post method to add this product in the cart but the button does not do it at all.
<div class="mb-3">
<input class="btn btn-primary" type="submit" value="Add to cart" asp-controller="Cart" asp-action="Add" asp-route-id="#Model.Id"/>
</div>
And this is the method in the cart's controller
[HttpPost]
public async Task<IActionResult> Add(int productId)
{
//Console.WriteLine("HelloCartAdd!");
//Some logic.
return RedirectToAction("Detail", "Product", productId);
}
When the route parameter is defined as asp-route-id="#Model.Id" the action method should use 'id' parameter name:
[HttpPost]
public async Task<IActionResult> Add(int id)
{
...
}
If the [HttpPost] attribute is applied to the action method add the formmethod="post" attribute to the <input> tag. I suppose the button is already located inside the form.
<form>
<input class="btn btn-primary" type="submit" formmethod="post" value="Add to cart" asp-controller="Cart" asp-action="Add" asp-route-id="#Model.Id" />
</form>
I have an async method in a controller that has an id parameter. In my view, I want to have a button that when clicked it passes a #document.SubmissionId variable to the function and execute it. How can I achieve that? Here is what I have so far:
Controller
private async Task<ActionResult> onPostSaveImage(string id){}
View
<input type="button" value="Send Images" class="btn btn-xs btn-outline-primary" onclick="location.href='#Url.Action("onPostSaveImage", "ICRDocumentPending")?id=' + #document.SubmissionId" />
Not enough just sign a method with async to be able work asynchronously when called from a view. It is necessary to derive your controller class from System.Web.Mvc.AsyncController, which implements IAsyncController interface. And code will become like below:
public class ICRDocumentPendingController : AsyncController
{
public async Task<ActionResult> onPostSaveImage(string id)
{
return await Task<ActionResult>.Factory.StartNew(() =>
{
/* some code */
//...
return View("ViewName", (object)id);
});
}
//...
}
View code:
<input type="button" value="Send Images"
class="btn btn-xs btn-outline-primary"
onclick="location.href='#Url.Action("onPostSaveImage", "ICRDocumentPending", new { id = document.SubmissionId }))'" />
I have a select in a form in the Layout of my web app that needs to be accessible from every page. The form sets a session variable that is required to load data on every page.
<form asp-page-handler="CustomerChange" method="post" class="navbar-form navbar-left">
<select name="Customer" id="Customer" class="form-control" onchange="this.form.submit()">
<option value="">Select Customer</option>
<option value="Vand">Vandalay</option>
<option value="Kram">Kramerica</option>
</select>
</form>
I know I can make a base PageModel and inherit from that on every page in order to respond to a OnPost e.g.
public abstract class BaseSecurePageModel : PageModel
{
[BindProperty]
public string Customer { get; set; }
public virtual void OnPostCustomerChange()
{
HttpContext.Session.SetString("Customer", Customer);
}
}
but this doesn't lend itself to having the model binded to the form and also requires that I remember to inherit from the base class in every page. Is there a correct way to handle forms that need to be available everywhere?
Try using a Controller instead and have your CustomerChange ActionResult specify a [Route()]. I use a Controller for most of my Layout items such as shopping carts, localization etc... in razor pages and works pretty well.
// Updated answer based on feedback from Steven B.
Below is an example of the localization I spoke about above. The form triggers a post against the SetLanguage method in the BaseController.cs
In the _Layout.cshtml file I have, in this instance, a partial view:
#Html.Partial("_SetLanguagePartial") // Used prior to .net core 2.1
<partial name="_SetLanguagePartial" /> // Used for .net core 2.1+
The html inside this _SetLanguagePartial.cshtml contains a form with the corresponding asp-controller and asp-action
<form id="selectLanguage" asp-controller="Base" asp-action="SetLanguage" asp-route-returnUrl="#returnUrl" method="post" class="form-horizontal" role="form">
<ul class="list-inline">
#foreach (var culture in cultureItems)
{
var countryIcon = "usa.png";
<li>
<button type="submit" class="btn btn-sm btn-link" name="culture" title="#culture.Text" value="#culture.Value">
#switch (culture.Text)
{
case "Japanese" :
countryIcon = "japan.png";
break;
case "Spanish" :
countryIcon = "spain.png";
break;
default:
break;
}
<img src="#Configuration["BlobStorage:StorageUrl"]/images/#countryIcon" alt="#culture.Text"/>
</button>
</li>
}
</ul>
</form>
BaseController.cs
[Route("[controller]/[action]")]
public class BaseController : Controller
{
[HttpGet]
public IActionResult GetCartViewComponent()
{
return ViewComponent("Cart");
}
[HttpPost]
public IActionResult SetLanguage(string culture, string returnUrl)
{
Response.Cookies.Append(
CookieRequestCultureProvider.DefaultCookieName,
CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture)),
new CookieOptions { Expires = DateTimeOffset.UtcNow.AddYears(1)}
);
return LocalRedirect(returnUrl);
}
}
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>
How can i pass to asp.net mvc action parameters like: line[first], line[second], line[third], people[john] etc?
For example we have html:
<form>
<input type="hidden" name="line[first]" value="hello" />`
<input type"submit" value="send" />
</form>
How we can take "line[first]" value when user clicks on send button?
[HttpPost, ValidateAntiForgeryToken]
public ActionResult ShowLogin(LoginModel model)
{
model.username;
model.password
}
instead of admin you can have
public ActionResult ShowLogin(FormCollection form)
{
var user = form["username"];
}