The Objective:
I have a post with an Ajax.BeginForm and my objective is to get The Button Id on the controller. I've seen examples using Html.BeginForm, But I need an Ajax form,
The Code: C# MVC3
View:
#using (Ajax.BeginForm("Save", "Valoration", new AjaxOptions() { HttpMethod = "Post", UpdateTargetId = "HvmDetailTabStrip", OnSuccess = "OnSuccessSaveValoration" }))
{
<div id ="HvmDetailTabStrip">
#(Html.Partial("_ValorationDetail"))
</div>
<button type="submit" style="display:none" id="db1"></button>
<button type="submit" style="display:none" id="db2"></button>
}
Controller:
[HttpPost]
public ActionResult Save(ValorationModel model)
{
if ("db1")
{
var result = ValorationService.Save(ValorationModel);
}
else
{
// ....
}
return PartialView("_ValorationDetail", ValorationModel);
}
You can get your buttons' values like this:
#using (Ajax.BeginForm("Save", "Valoration", new AjaxOptions() { HttpMethod = "Post", UpdateTargetId = "HvmDetailTabStrip", OnSuccess = "OnSuccessSaveValoration" }))
{
<div id ="HvmDetailTabStrip">
#(Html.Partial("_ValorationDetail"))
</div>
<button type="submit" name="submitButton" value="db1"></button>
<button type="submit" name="submitButton" value="db2"></button>
}
And in your controller you can write:
[HttpPost]
public ActionResult Save(ValorationModel model)
{
string buttonValue = Request["submitButton"];
if(buttonValue == "db1"){
var result = ValorationService.Save(ValorationModel);
}else
{
....
}
return PartialView("_ValorationDetail", ValorationModel);
}
Or if count of parameters you pass in method doesn't matter, you can use this:
[HttpPost]
public ActionResult Save(ValorationModel model, string submitButton)
{
if(submitButton == "db1"){
var result = ValorationService.Save(ValorationModel);
}else
{
....
}
return PartialView("_ValorationDetail", ValorationModel);
}
Other way how you can solve your problem is here ASP.Net MVC - Submit buttons with same value
Related
i'm making a webbapplication with ASP.NET MVC and im trying to edit my list of objects. If i for example add a product to the site and then click on edit for that product to change the prize i just get a new object with the new prize instead of changing the prize to the product.
So the problem is that instead of updating the products it just adds a new one.
this is how my controller for the products looks like:
using auktioner_MarcusR91.Data;
using auktioner_MarcusR91.Models;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace auktioner_MarcusR91.Controllers
{
public class InventoryController : Controller
{
private readonly AppDbContext _db;
public InventoryController(AppDbContext db)
{
_db = db;
}
public IActionResult Index()
{
IEnumerable<Inventory> objInventoryList = _db.Inventories;
return View(objInventoryList);
}
//GET
public IActionResult Create()
{
return View();
}
//Post
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(Inventory inventory)
{
_db.Inventories.Add(inventory);
_db.SaveChanges();
return RedirectToAction("index");
}
//GET
public IActionResult Edit(int? id)
{
if (id == 0 || id == 5)
{
return NotFound();
}
var inventoryFromDb = _db.Inventories.Find(id);
if (inventoryFromDb == null)
{
return NotFound();
}
return View(inventoryFromDb);
}
//Post
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Edit(Inventory inventory)
{
if (ModelState.IsValid)
{
_db.Inventories.Update(inventory);
_db.SaveChanges();
return RedirectToAction("index");
}
return View(inventory);
}
}
}
I think there is something wrong in my controller.
However here is also my view for when i edit a product:
#model Inventory
<form method = "post" asp-action = "Edit">
<div class = "border p-3 mt-4">
<div class = "row pb-2">
<h2 class = "text-primary">Edit Inventory</h2>
<hr />
</div>
<div class = "mb-3">
<label asp-for ="inventoryName"></label>
<input asp-for = "inventoryName" />
<label asp-for ="finalPrize"></label>
<input asp-for = "finalPrize" />
<label asp-for ="inventoryDesc"></label>
<input asp-for = "inventoryDesc" />
<p>1 för "Transport</p>
<p>2 för "Smycken"</p>
<p>3 för "Hushåll"</p>
<p>4 för "Dekoration"</p>
<select asp-for = "categoryId">
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
</select>
</div>
<button type = "submit" class = "btn btn-primary" width = "100px">Update</button>
<a asp-controller = "Inventory" asp-action = "index" class = "btn btn-secondary" style = "width: 100px">Back to products</a>
</div>
</form>
You have to add a primary key inventoryId as a hidden input, without this key , you inventory instance looks like a new one for EF.
And since you are using [ValidateAntiForgeryToken] in the action, add this to view with another form syntax
#using (Html.BeginForm("Edit", "Inventory", FormMethod.Post))
{
#Html.AntiForgeryToken()
<input type="hidden" asp-for="inventoryId" value="#Model.inventoryId" />
....
<button type = "submit" class = "btn btn-primary" width = "100px">Update</button>
<a asp-controller = "Inventory" asp-action = "index" class = "btn btn-secondary" style = "width: 100px">Back to products</a>
</div>
}
and IMHO your update code could be like this
if (ModelState.IsValid)
{
var inventoryFromDb = _db.Inventories.Find(inventory.inventoryId);
if (inventoryFromDb == null)
{
return NotFound();
}
_db.Entry(inventoryFromDb).CurrentValues.SetValues(inventory);
var result= _db.SaveChanges();
}
You have to send your record id to the controller by clicking update button of the record . something like this :
<a class="btn btn-warning btn-sm btn-margin" asp-controller="ContextController" asp-action="UpdateAction" ***asp-route-id="#item.Id***">Update</a>
which #item is the object of the model sent to the view .
And the action would be :
[HttpGet]
public IActionResult UpdateAction(int id)
{
Model record = _Context.GetById(id);
return View("UpdateFormPageOrModal",record);
}
And after updating the form and clicking the submit button of the view data will send to action :
[HttpPost]
public IActionResult UpdateAction(Model record)
{
var result = _Context.UpdateBy(record);
ViewData["Result"] = result.Message;
if (result.IsSucceeded)
{
_UnitOfWork.Save();
return RedirectToAction("TheGridView");
}
return View("UpdateView",record);
}
where UpdateBy() method should be like this :
public void UpdateBy(T entity)//entity is an object of the DbSet<Model>
{
var state = _Context.Entry(entity).State;
if (state == EntityState.Detached)
{
_Context.Attach(entity);
}
_Context.Entry(entity).State = EntityState.Modified;
}
I have a Controller Action which returns a JsonResult instead of a View. Depending on whether or not the method completed successfully, I need to add and execute a Javascript. I've added an OnActionExecuted ActionFilter to the method to generate and add the script, but because it's returning a JsonResult, I don't have a ViewResult to which I can add my script.
I'm a bit out of ideas on this. Does anyone have a solution to this problem or know of another way to approach this issue?
Controller method:
[InsertJavascript]
public async Task<ActionResult> Create(CreateAccountPageV2 currentPage, CreateAccountViewModel model)
{
//some logic here
return return Json(new
{
success = true,
redirectUrl = false,
html = partialViewToString,
invalidFields = InvalidFields
});
}
Action Filter:
[AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public class InsertJavascriptAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
var jsonResult = filterContext.Result as JsonResult;
if (jsonResult == null)
{
return;
}
var script = GenerateMyJavascript();
// some way to send the script to View and execute it
}
}
Edit: The request is made from an Ajax Form contained in a Partial View.
Partial View file where the request is made to the Controller:
#model CreateAccountViewModel
#using (Ajax.BeginForm(null, null, new AjaxOptions
{
HttpMethod = "Post",
Url = Model.Url,
OnBegin = #OnBeginId,
OnSuccess = #OnSuccessId,
OnFailure = #OnFailureId
}, new
{
#class = "form--tight",
data_component = "Auth",
data_auth_type = "create",
data_id = #guid,
}))
{
<fieldset>
// input fields
<div class="Auth-createAccount-submitContainer">
<p class="required">*#Model.RequiredFieldLabel</p>
<button type="submit" id="createFormSubmitBtn" class="btn btn-primary Auth-createAccount-submitButton">
</button>
</div>
</fieldset>
}
I have come across a weird issue, I hope someone can explain why the following is happening.
My controller:
MasterModel main = new MasterModel();
public ActionResult Index()
{
return View();
}
[HttpGet]
public ActionResult VehicleDetail()
{
pageSessionSetup();
return PartialView("VehicleDetail", main.Vehicle);
}
[HttpPost]
public ActionResult VehicleDetail(VehicleDetailDisplay model)
{
ModelState.AddModelError("", "Errors occured");
main.Vehicle = model;
pageSessionSetup();
return PartialView("VehicleDetail", main.Vehicle);
}
Updated With View
My View:
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
#using (Ajax.BeginForm("VehicleDetail", "Operator", null, new AjaxOptions
{
UpdateTargetId = "VehicleDetail",
InsertionMode = InsertionMode.Replace,
HttpMethod = "Post"}, new { id = "VehicleDetail" }))
{
#Html.Partial("_ValidationSummary", ViewData.ModelState)
<div class="panel panel-default panel-body">
...
</div>
<div class ="col-lg-7 col-md-7 col-sm-7 col-xs-7 row">
<button type="submit" value="Save" class="btn btn-lg btn-green col-lg-2 col-md-5 col-sm-7 col-xs-7">Save</button>
</div>
}
And on my partial view I have a submit button, but when I click the submit button one time then the form gets submitted more than one time.
UPDATE:
use Html.BeginForm("ActionName", "ControllerName", FormMethod.Post) instead of Ajax.BeginForm() OR check if you have included the jquery.unobtrusive-ajax.min.js twice in your page(s)(in partial views also).
--------------------------------------------------------------------------------------------------------
#using (Html.BeginForm("ActionName", ""ControllerName", FormMethod.Post))
{
<label>SomeLabel</label>
...
<input type="submit" value="Button" /></p>
}
I am working with sample from codeproject http://www.codeproject.com/Tips/1011040/Upload-and-Delete-Video-File-to-Microsoft-Azure-Bl
I have created an index.cshtml in the way of
that is
#model List<string>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#using (Html.BeginForm("Add", "Blob", FormMethod.Post, new
{enctype = "multipart/form-data" }))
{
<div>
<input type="file" name="pic" id="pic" />
<input type="submit" value="Upload Now" id="s1" />
</div>
}
<ul>
#foreach (var item in Model)
{
<li>
<input type="button" name="b1" id="b1"
value="Delete"
onclick="Remove('#item')" />
<video src="#item" height="200" width="200" controls />
</li>
}
</ul>
#section scripts{
<script>
function Remove(x) {
alert(x);
var uri = "/Blob/remove";
$.post(uri, { name: x }, function (y) {
window.location.href = "/blob/index";
alert(y);
});
}
</script>}
and my Controller class is :
public class BlobsController : Controller
{
//
// GET: /Blobs/
BlBlobs objbl = new BlBlobs();
public ActionResult Index()
{
//return View();
return View(objbl.GetBlobList());
}
[HttpPost]
public ActionResult Add(HttpPostedFileBase pic)
{
objbl.AddBlob(pic);
return RedirectToAction("Index");
}
[HttpPost]
public string Remove(string name)
{
objbl.DeleteBlob(name);
return "Blob Removed Successfully";
}
}
That give me pretty nice browse/upload form, but fails on upload click with 404 error. The question is - how to call the add method correctly in this index.cshtml file?
Your controller is called BlobsController so that would give you a route of /blobs/{action} with the default route, however in your view your actions are looking for a controller called blob. Either change the name of your controller
public class BlobController : Controller
{
//...
}
Or update your views to use the correct controller name.
Html.BeginForm("Add", "Blobs", FormMethod.Post, new
{enctype = "multipart/form-data" }))
I'm quite new with ASP so be tolerant :)
I've got a view with a search form in it.
View
<div id="search-form" class="row search-form">
#using(Ajax.BeginForm("Search",
"Home",
new AjaxOptions
{
UpdateTargetId = "result",
InsertionMode = InsertionMode.Replace,
LoadingElementId = "ajax_loader"
},
new { #class = "form-horizontal col-sm-offset-3 col-sm-6" }
))
{
<div class="form-group">
<div class="col-sm-10">
#{string query = string.Empty;}
#Html.EditorFor(x => query, new { htmlAttributes = new { #class = "form-control" } })
</div>
<input id="submitbtn" type="submit" value="Search" class="btn btn-primary col-sm-2" />
</div>
}
</div>
<div id="ajax_loader" style="display:none">
<img src="~/Content/Images/ajax_loader.gif" alt="Ajax Loader" />
</div>
<div id="result"></div>
Controller
[AllowAnonymous]
public ActionResult Index()
{
ViewBag.Title = "serach form";
return View();
}
public async Task<ActionResult> Search(string query)
{
WinesApiController winesCtrl = new WinesApiController();
var listOfWines = await winesCtrl.Get(query);
return PartialView("_WineResult", listOfWines);
}
The Search method in my controller returns a PartialView. When I decorate all the methodsin the controller with the [AllowAnonymous] attribute, everything works very well. But what I would like it to display the form for anybody, but as long as you click on the search button, you need to be logged in. So I deleted all the AllowAnonymous attributes but on the Index method (the one which render my View). Now, the result of my call is not shown anymore (which is quite ok) but I am not redirected to the login view.
My question is then, why the call to the partial view does not redirect me to the login view ? I guess that authentification is performed because I cannot see the results of the submit action, but why am I not redirected ?
You are making an ajax call to the Search Action right? The default asp.net mvc AuthorizeAttribute does not return an appropriate response when authorization fails on ajax calls.
You could write your own Authorization Filter, that returns a better response, like this:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
public sealed class YourAuthorizeAttribute : AuthorizeAttribute {
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) {
var httpContext = filterContext.HttpContext;
var request = httpContext.Request;
var response = httpContext.Response;
if (request.IsAjaxRequest()) {
response.SuppressFormsAuthenticationRedirect = true;
response.StatusCode = (int)HttpStatusCode.Unauthorized;
response.End();
}
base.HandleUnauthorizedRequest(filterContext);
}
}
With this filter, you could have a default javascript code to handle all unauthorized scenarios:
$.ajaxSetup({
statusCode: {
401: function (response) {
var returnUrl = encodeURI(window.location.pathname + window.location.search);
var loginUrl = '/custumer/login?ReturnUrl=' + returnUrl;
window.location.href = loginUrl;
}
}
});
What happens if you put an Authorize attribute on the action?
[Authorize()]
public async Task<ActionResult> Search(string query)
{
WinesApiController winesCtrl = new WinesApiController();
var listOfWines = await winesCtrl.Get(query);
return PartialView("_WineResult", listOfWines);
}