I use checkboxes in an MVC5 Razor View and retrieve the checkbox values from Controller successfully by using ViewBag as shown below:
Controller:
public ActionResult Create()
{
ViewBag.RolesList = new SelectList(
this.RoleManager.Roles.ToList(), "Id", "Name");
return PartialView("_Create");
}
View:
#model Identity.ApplicationGroup
#foreach (var item in (SelectList)ViewBag.RolesList)
{
<div class="checkbox">
<label>
<input type="checkbox" name="#item" value="#item.Text">
#item.Text
</label>
</div>
}
However, I cannot pass the checkbox values to the Controller via AJAX as shown below while all of the other parameters are posted without any problem. So, how can I post them as the model values?
View:
function insert(event) {
var formdata = $('#frmCreate').serialize();
$.ajax({
type: "POST",
url: '#Url.Action("Insert", "GroupsAdmin")',
cache: false,
dataType: "json",
data: formdata
});
};
Controller:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Insert([Bind(Exclude = null)] ApplicationGroup
applicationgroup, params string[] selectedRoles)
{
...
}
Related
I am trying to get the id of a clicked button and then send that buttonId to the variable categoryId in the action AddItem of the controller ItemController using ajax but I am relatively new to ajax and am not sure where I am going wrong.
html code in view:
<button id="1" onclick=" buttonClicked(this.id)">button1</button>
javascript code in view that gets the id of the button clicked:
function buttonClicked(buttonId) {
$.ajax({
url: '<%: Url.Action("ItemController, AddItem")%>',
data: { 'id': buttonId },
type: "POST",
cache: false,
});
}
Controller code:
[HttpPost]
public ActionResult AddItem(int buttonId)
{
var categoyId = Convert.ToString(buttonId);
return View();
}
I would like to post a request via AJAX to a Controller with a model prefix. I need a prefix as I have two forms on one page with similiar model properties ("asp-for" is generating similiar IDs and Names). I'm using .NET Core 3.1.
Request post works fine without a prefix. When I'm using a prefix like in the example below, passed model is null in Controller:
Controller with prefix
[HttpPost]
public async Task<IActionResult> Save([Bind(Prefix="ShipmentAddress"), FromBody]ShipToAddressViewModel model)
{
// model is null
...
return PartialView(ShipmentAdressFormView, model);
}
View with prefix
In my View I set the HTMLFieldPrefix as well:
#model ShipToAddressViewModel
#{
ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix = "ShipmentAddress";
}
...
$("body").on('submit','#formShipmentAddress', function (e) {
// Getting the data (see passed JSON below)
var formData = new FormData(<HTMLFormElement>document.getElementById('formShipmentAddress'));
var object = {};
formData.forEach(function (value, key) {
object[key] = value;
});
var data = object;
$.ajax({
type: "POST",
url: url,
data: JSON.stringify(data),
contentType: "application/json; charset=utf-8",
success: (data) => {
success(data);
}
});
});
Passed JSON payload with prefix
{"ShipmentAddress.ID":"3","ShipmentAddress.Name":"Eddard Stark","ShipmentAddress.Name2":"c/o Ned",..."}
Model
public class ShipToAddressViewModel
{
public int ID { get; set; }
[Display(Name="Name")]
public string Name { get; set; }
[Display(Name = "Name 2")]
public string Name2 { get; set; }
...
}
UPDATE
If I remove the prefix from keys of my objects, then it works, though more like a work around (Model binding starts by looking through the sources for the key ShipmentAddress.ID. If that isn't found, it looks for ID without a prefix.):
// Getting the data (see passed JSON below)
var formData = new FormData(<HTMLFormElement>document.getElementById('formShipmentAddress'));
var object = {};
formData.forEach(function (value, key) {
object[key.replace("ShipmentAddress.","")] = value;
});
var data = object;
For Asp.Net Core, there are two ways to bind the model, ModelBinding and JsonInputFormatter. For sending request with json, it will use JsonInputFormatter. Bind will not work with JsonInputFormatter.
Here is a working demo like below:
1.View:
#{
ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix = "ShipmentAddress";
}
#model ShipToAddressViewModel
<form id="formShipmentAddress">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="ID" class="control-label"></label>
<input class="form-control" asp-for="ID">
<span asp-validation-for="ID" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Name" class="control-label"></label>
<input class="form-control" asp-for="Name">
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Name2" class="control-label"></label>
<input class="form-control" asp-for="Name2">
<span asp-validation-for="Name2" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
#section Scripts
{
<script>
$("body").on('submit', '#formShipmentAddress', function (e) {
e.preventDefault();
var id = parseInt($("#ShipmentAddress_ID").val());
var name = $("#ShipmentAddress_Name").val();
var name2 = $("#ShipmentAddress_Name2").val();
var data = {
ID: id,
Name: name,
Name2: name2
};
$.ajax({
type: "POST",
url: "/Home/Save",
data: JSON.stringify(data),
contentType: "application/json; charset=utf-8",
success: (data) => {
success(data);
}
});
});
</script>
}
2.Controller:
public async Task<IActionResult> Save([FromBody]ShipToAddressViewModel model)
{
//do your stuff...
}
3.Result:
Working in ASP.NET Core where I'm trying to POST a List of Items through Ajax. Ideally, I would like to pass the entire ReportViewModel but I haven't been able to match the signature correctly (since passing a DateTime or a List isn't that easy).
My question
How to POST a List<Object> from the view with Ajax to the controller?
OR How to POST a Model from the view with Ajax to the controller?
I currently have the following code:
Models
public class ReportViewModel {
public int ReportType { get; set; };
public DateTime DateFrom { get; set; };
public DateTime DateTo { get; set; };
public List<Item> ItemList{ get; set; };
}
public class Item {
// Properties are simple types
}
View (ReportView)
#model Namespace.ViewModels.ReportViewModel
#inject Namespace.Resource Resources
<!-- HTML code -->
<form>
<button class="ui button" type="submit" onclick="return createPDF();">#Resources.Save</button>
</form>
<script>
function createPDF() {
alertify.set('notifier', 'position', 'bottom-left');
$.ajax({
type: "POST",
url: "CreatePDF",
data: JSON.stringify({
reportType: #Model.ReportType,
ticksDateFrom: #Model.DateFrom.Ticks,
ticksDateTo: #Model.DateTo.Ticks
#* TODO: Add the List<Items> itemList (from #Model.ItemList)*#
}),
contentType: 'application/json',
// Code for success and error
});
return false;
};
</script>
Controller (ReportController)
[HttpPost]
public JsonResult CreatePDF([FromBody] dynamic data) {
// Lots of code
return Json(new { isError = false });
}
/* When passing the entire model
* [HttpPost]
* public JsonResult CreatePDF([FromBody] ReportViewModel model) {
* // Lots of code
* return Json(new { isError = false });
* }
*/
I tried passing the model as seen below but that leaves me with the parameter in the controller being null or as a new "empty" object, depending if I use [FromBody] or not.
$.ajax({
type: "POST",
url: "CreatePDF",
data: #Html.Raw(Json.Serialize(Model)),
contentType: 'application/json',
// Code for success and error
});
You can use the BeginForm in your view that posts to a controller:
#model Namespace.ViewModels.ReportViewModel
#inject Namespace.Resource Resources
#using (Html.BeginForm("CreatePDF", "[PDFControllerName]", FormMethod.Post, new { #id = "pdfCreatorForm" }))
{
<!-- Send parameters to a controller like this (invisibly) -->
#Html.HiddenFor(m => m.ReportType)
#Html.HiddenFor(m => m.DateFrom.Ticks)
#Html.HiddenFor(m => m.DateTo.Ticks)
#Html.HiddenFor(m => m.ItemList) <!-- Send the List<Items> -->
<button type="submit" class="ui button" onclick="alertify.set('notifier', 'position', 'bottom-left')">#Resources.Save</button>
}
And then you don't need the JavaScript any more, another thing to keep in mind is to keep as much functionality on your server side as you can.
If you POST the form to a controller, you can access the view's parameters etc like this:
public JsonResult CreatePDF(ReportViewModel formData)
{
int reportType = formData.ReportType;
DateTime ticksDateFrom = formData.DateFrom.Ticks;
DateTime ticksDateTo = formData.DateTo.Ticks;
List<Items> itemList = formData.ItemList;
// Lots of code
}
And, you actually doesn't need to specify that it's taking in a HttpPost :)
I don't know what exactly I changed to make it work but the following compiles correctly. Could be the processData: true and cache: false properties?
Controller
[HttpPost]
public JsonResult CreatePDF([FromBody] ReportViewModel model)
{
// Lots of code
return Json(new { isError = false });
}
View (JS only)
$.ajax({
type: "POST",
url: "CreatePDF",
data: JSON.stringify(#Html.Raw(Json.Serialize(Model))),
contentType: 'application/json; charset=utf-8',
processData: true,
cache: false,
// Code for success and error
});
I am creating an ASP.NET MVC application. I am currently developing a search page where both the search box and the table of results are displayed on the same page. To do this I have used Partial Views and AJAX/JSON calls with a viewmodel. After entering the two search terms in the textbox, both are null in the controller after being passed through ajax.
Here is the code:
ViewModel:
public class ExampleViewModel
{
public string search { get; set; }
public string search2 { get; set; }
}
Controller:
[HttpPost]
public ActionResult Search(ExampleViewModel searchTerm)
{
var searchList = db.UserLists.Where(x => x.LastName.Contains(searchTerm.search));
return PartialView("_SearchResultsPartial", searchList);
}
Body of Index View:
<body>
<div>
#Html.TextBoxFor(model => model.search)
#Html.TextBoxFor(model => model.search2)
<input type="submit" value="Search" onclick="return getSearchResults()"/>
</div>
<div id="search-results">
</div>
<script>
var exViewModel = {
search: $('#search').val(),
search2: $('#search2').val()
}
function getSearchResults() {
$.ajax({
type: "POST",
data: JSON.stringify(exViewModel),
dataType: "json",
contentType: "application/json",
url : "/View/Search/",
success: function (result) {
$("#search-results").html(result);
}
});
}
</script>
Again, after setting a breakpoint on the Search [POST] method, the ExampleViewModel's terms are null.
At first sight, it seems that you have to retrieve the values within the function scope:
function getSearchResults() {
//Read these values on button click
var exViewModel = {
search: $('#search').val(),
search2: $('#search2').val()
}
$.ajax({
type: "POST",
data: JSON.stringify(exViewModel),
dataType: "json",
contentType: "application/json",
url : "/View/Search/",
success: function (result) {
$("#search-results").html(result);
}
});
}
Otherwise, the exViewModel is just determined on page load.
In the documentation https://msdn.microsoft.com/en-us/library/system.web.mvc.ajax.ajaxoptions%28v=vs.118%29.aspx I can't find anything that is the equivalent of the data parameter in something like
$.ajax({
url: '#Url.Action("AutoLocate")',
type: 'GET',
data: postData,
success: function(result) {
// process the results from the controller
}
});
Using Razor syntax for a form, e.g.
#using (Ajax.BeginForm("GenerateMasterLink", "SurfaceAssets", new AjaxOptions { HttpMethod = "POST", InsertionMode = InsertionMode.Replace, UpdateTargetId = "masterLinkHolder" })) { ... }
how do I tell it that I want a JavaScript variable, say,
var str = "here's a string, bro!";
to be passed in to the corresponding controller
public ActionResult GenerateMasterLink (string str)
{
...
}
??????
Try like this.
$.ajax({
url: '#Url.Action("AutoLocate")',
type: 'GET',
data: str,
success: function(result) {
// process the results from the controller
}
});
and in controller
public ActionResult GenerateMasterLink (string str)
{
...
}
If you have more than one parameter then
$.ajax({
url: '#Url.Action("AutoLocate")',
type: 'GET',
data: {id: 12,name:'Name'},
success: function(result) {
// process the results from the controller
}
});
public ActionResult GenerateMasterLink (int id,string name)
{
...
}
You can pass form data into the action GenerateMasterLink using a C# type you create in your server code with one property for each of the properties in your javascript object. It might looks something like this:
public class FormData
{
public int PropertyName1 { get; set; }
public string PropertyName2 { get; set; }
}
public ActionResult GenerateMasterLink (FormData form)
{
...
}
Make sure the data being sent is valid JSON (use JSON.stringify() in JavaScript to convert a JavaScript object to JSON). Also, you can get the value into your view using the ViewBag (or model). Here's how you'd set it in the ViewBag:
public ActionResult GenerateMasterLink (FormData form)
{
ViewBag.SomeNameOfYourChoosing = form.PropertyName1;
return View();
}
Then in the Razor:
#ViewBag.SomeNameOfYourChoosing