Ajax Post: ASP.NET MVC action is receiving empty object - ajax

I have this form:
#model CupCakeUI.Models.CupCakeEditViewModel
#using (Html.BeginForm(null, null, FormMethod.Post, new { id = "createFrm" }))
{
<div class="form-group">
<div class="editor-label">
#Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
<input type="text" id="Name" name="Name" value="#Model.Name" />
</div>
<div class="editor-label">
#Html.LabelFor(model => model)
</div>
<div class="editor-field">
<input type="text" id="Price" name="Price" value="#Model.Price" />
</div>
<div class="col-md-offset-2 col-md-10">
<input type="button" id="btnCreate" value="Create" class="btn btn-default" />
</div>
</div>
}
I am trying to use ajax post to send data to the Action Method, however its always receiving empty object. I have done that several times in the past, and now i tried different ways which not working, The code:
$(document).ready(function () {
$("#btnCreate").click(function () {
var name = $("#Name").val();
var price = $("#Price").val();
var cupCakeEditModel = { "CupCakeId": 0, "Name": name, "Price": price };
var json = JSON.stringify(cupCakeEditModel);
$.ajax({
type: 'POST',
url: "/CupCake/Create",
data: JSON.stringify(cupCakeEditModel),
contentType: 'application/json',
success: function () {
alert("succes");
},
error: function () {
alert("error");
}
});
})
})
Its showing this in the console when logging:
This is the Action Method and Class used:
[HttpPost]
public JsonResult Create (CupCakeUI.Models.CupCakeEditViewModel cupCakeEditModel)
{
var cupCake =
CupCakeData.Save(cupCakeEditModel);
return Json("cupCake",
JsonRequestBehavior.AllowGet);
}
This the class:
public class CupCakeEditViewModel
{
public int CupCakeId;
[Display(Name = "CupCake Name")]
public string Name;
public string Price;
}
I have also used this, but not working:
$("#btnCreate").click(function () {
var cupCakeEditModel =
$("#createFrm").serialize();
$.ajax({
url: "/CupCake/Create",
type: "POST",
data: cupCakeEditModel,
success: function (response) {
alert("Success");
},
error: function (response) {
}
});
})
And several answers i found on the forum, but it seems something weird!

You model contains only fields, and the DefaultModelBinder does not bind fields, only properties. Change the model to
public class CupCakeEditViewModel
{
public int CupCakeId { get; set; }
[Display(Name = "CupCake Name")]
public string Name { get; set; }
public string Price { get; set; }
}

Related

ajax post data null in mvc core controller method

I faced this problem here , but I can not solve it . I searched a lot and tried every solution I found on the similar post . so if there is any help to my case . my part of my app which I found the problem in , first here is my view , I have Categories dropdown when I choose a category I will load the property of that value in a table.
#model Demo.Models.ViewModel.DeviceVM
<form method="post">
<input hidden asp-for="#Model.device.ID" />
<div class="border p-3">
#*putting the page label*#
<div class="row">
<h3 class="text-info pl-3 pb-3">Create Device</h3>
</div>
#*fifth Row => Category List*#
<div class="form-group row">
#*field Label*#
<div class="col-4">
<label asp-for="#Model.device.CategoryID"></label>
</div>
#*field Text*#
<div class="col-8">
<select asp-for="#Model.device.CategoryID" asp-items="#Model.CategoryDropDown" class="form-control"
id="CategoryList">
<option value="">-- Select Category --</option>
</select>
<span asp-validation-for="#Model.device.CategoryID" class="text-danger"></span>
</div>
</div>
<div class="form-group row">
<div class="col-4">
<label>Category Properties</label>
</div>
<div class="col-8">
<table class="table table-bordered table-striped">
<thead class="thead-dark">
<tr>
<th>Property</th>
<th>Value</th>
</tr>
</thead>
<tbody id="plist">
</tbody>
</table>
</div>
</div>
#*Seventh Row => Buttons*#
<div class="form-group">
<div class="col-8 offset-4 row">
#*Save Button*#
<div class="col">
<input type="submit" value="Save" asp-action="Create" class="btn btn-info w-100" />
</div>
#*Back Button*#
<div class="col">
<a class="btn btn-success w-100" asp-action="Index">Back</a>
</div>
</div>
</div>
</div>
</div>
</div>
</form>
#section Scripts
{
<script>
$(function ()
{
$('#CategoryList').on("change", function () {
var _category = $('#CategoryList').val();
var obj = {CategoryID:_category};
AjaxCall("GetCategoryProperty", JSON.stringify(obj), 'POST').done(function (response) {
console.log(JSON.stringify(obj));
if (response.length > 0)
{
console.log("i'm here ");
}
}).fail(function (error) {
alert(error.StatusText);
});
});
});
function AjaxCall(url, data, type) {
return $.ajax({
url: url,
type: type ,
data: data ,
contentType: 'application/json; charset=utf-8',
dataType:'json'
});
}
</script>
}
here is my Category Model
public class Category
{
[Key]
public int ID { get; set; }
[Required,MaxLength(15),Display(Name ="Category Name")]
public string CatName { get; set; }
public virtual ICollection<Category_Property> categoryprperties {get;set;}
}
here is my Function in the view which always receive 0 in it's parameter
[HttpPost]
public JsonResult GetCategoryProperty([FromBody]int CategoryID)
{
DeviceVM obj = new DeviceVM();
var _CategoryProperty = (from cp in _db.Category_Property
join p in _db.Property on cp.PropertyID equals p.ID
where cp.CategoryID == CategoryID
select new { cp.CategoryID, p.Description, cp.PropertyID });
return Json(_CategoryProperty );
}
I opened the inspect in the browser I it did not reach the message inside the if block because ajax always send 0 for the category id , which I asking for a help to get work.
Two ways you can achieve your requirement.
The first way you can post the id by form like below:
1.Change JSON.stringify(obj) to obj and remove contentType: 'application/json; charset=utf-8',:
$(function ()
{
$('#CategoryList').on("change", function () {
var _category = $('#CategoryList').val();
var obj = {CategoryID:_category};
//change here...
AjaxCall("/home/GetCategoryProperty", obj, 'POST').done(function (response) {
console.log(JSON.stringify(obj));
if (response.length > 0)
{
console.log("i'm here ");
}
}).fail(function (error) {
alert(error.StatusText);
});
});
});
function AjaxCall(url, data, type) {
return $.ajax({
url: url,
type: type ,
data: data ,
//contentType: 'application/json; charset=utf-8',
dataType:'json'
});
}
2.Remove [FromBody] or add [FromForm]:
public class HomeController : Controller
{
[HttpPost]
public JsonResult GetCategoryProperty(int CategoryID)
{
//...
}
}
The second way you can post it by body, you need create a model like below then reserve your js code:
public class Test
{
public int CategoryID { get; set; }
}
Change your action:
public class HomeController : Controller
{
[HttpPost]
public JsonResult GetCategoryProperty([FromBody] TestM model)
{
//...
}
}

Razor Pages Model Binding in Partial View after post form

I trying to achieve to following: let's say I have a Create VM form. This is all very standard with stuff:
Model
[BindProperty]
public NewVM NewVM { get; set; }
NewVM Model (part of):
public string Name { get; set; }
public int SelectedTemplateId { get; set; }
public List<Templates> Templates { get; set; }
Template Model (part of):
public int Id{ get; set; }
public string Name { get; set; }
Form (part of)
<form method="post">
<div class="form-group row">
<label for="vmname" class="col-sm-4 col-form-label col-form-label-sm">Virtual Machine Name</label>
<div class="col-sm-8">
<input type="text" class="form-control form-control-sm">
</div>
</div>
</form>
A part of the Create VM form is selecting a template. This is dependent of the Cluster selected. This a presented as a dropdown box
<div class="form-group row">
<label class="col-sm-4 col-form-label col-form-label-sm">Cluster</label>
<div class="col-sm-8">
#Html.DropDownListFor(x => Model.ClusterId, new SelectList(Model.Clusters, "Id", "Name"), "Please select", htmlAttributes: new { #class = "form-control form-control-sm", id = "clusters" })
#Html.ValidationMessageFor(x => x.Tenant.ClusterId, "", new { #class = "text-danger" })
</div>
</div>
So far so good. When a cluster is selected the following Ajax call is made to retrieve the templates available for that cluster:
Javascript:
$(function () {
$("#clusters").change(function () {
var host = $(this).val();
$.ajax({
type: "POST",
url: "/VM/AddVmDC2?handler=GetTemplates",
beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
data: { "host": host },
success: function (response) {
$("#templatebody").html(response);
},
failure: function (response) {
alert(response.responseText);
},
error: function (response) {
alert(response.responseText);
}
});
});
});
Backend
public async Task<IActionResult> OnPostGetTemplates(int clusterid)
{
_apilocation = _config["apiurl"];
var templates = await helper.QueryApi(_apilocation, "/api/inventory/template?clusterid=" + clusterid);
NewVM.Templates = JsonConvert.DeserializeObject<List<Templates>>(templates);
return Partial("_Templates", Tenant);
}
Partial View
#model NewVM
#Html.DropDownListFor(x => x.SelectedTemplateId , new SelectList(Model.Templates, "Id", "Name"), "Please select", htmlAttributes: new { #class = "form-control form-control-sm", id = "templates" })
#Html.ValidationMessageFor(x => x.SelectedTemplateId , "", new { #class = "text-danger" })
Partial view is called in Form
<div class="form-group row">
<label class="col-sm-4 col-form-label col-form-label-sm">Templates</label>
<div class="col-sm-8" id="templatebody">
#{
<partial name="_Templates" for="NewVM"/>
}
</div>
</div>
The problem is that when I post the form SelectedTemplateId is always null. What am I doing wrong here. Can someone help me explain why SelectedTemplateId is always null.
Thanks !
You ajax data is
data: { "host": host },
and your handler is
public async Task<IActionResult> OnPostGetTemplates(int clusterid)
you need to change int clusterid to int host,so that you can get the data in ajax.
And if your SelectedTemplateId is still null,can you share your Tenant structure,and check the SelectedTemplateId in it.

AJAX post a modelview to my controller

I'm making a website where a moderator can at a certain pc part. This is just a form on my website. I want the form to post trough AJAX so it doesn't refreshed after a part has been added. I'm making the application with ASP.net Core 2.0
This is my view:
#model PcBuildAddViewModel
#{
ViewData["Title"] = "Add";
}
<div class="form-container">
<form id="AddPcForm" class="form-wrapper" method="post">
<p>Name:</p>
<input asp-for="#Model.PcPart._Name" type="text" class="form-control"/>
<br/>
<p >Type:</p>
<div class="form-select">
<select asp-for="#Model.PcPart._Type" asp-items="#Model.AllTypes">
</select>
</div>
<br/>
<p>Info:</p>
<input asp-for="#Model.PcPart.Information" type="text" class="form-control"/>
<br/>
<p>Properties:</p>
<div class="form-select">
<select asp-for="#Model.Properties" asp-items="#Model.AllProperties" multiple="multiple">
</select>
</div>
<br/>
<p>Image:</p>
<input asp-for="#Model.Image" type="file" class="inputfile inputfile-1"/>
<label asp-for="#Model.Image">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="17" viewBox="0 0 20 17">
</svg> <span>Choose a fileā€¦</span>
</label>
<br/>
<button class="btn btn-1 btn-1e" type="submit">
<span>Add</span>
</button>
</form>
</div>
My viewmodel that i want to post trough AJAX:
public class PcBuildAddViewModel
{
public List<SelectListItem> AllProperties { get; } = new List<SelectListItem>();
public List<SelectListItem> AllTypes { get; } = new List<SelectListItem>();
public IFormFile Image { get; set; }
public PcPart PcPart { get; set; }
public List<int> Properties { get; set; }
public PcBuildAddViewModel()
{
}
public PcBuildAddViewModel(List<Propertie> allProperties, List<string> allTypes)
{
foreach (string type in allTypes)
{
SelectListItem listItem = new SelectListItem
{
Text = type,
Value = type
};
AllTypes.Add(listItem);
}
foreach (Propertie propertie in allProperties)
{
SelectListItem listItem = new SelectListItem
{
Text = propertie._Value,
Value = propertie.Id.ToString()
};
AllProperties.Add(listItem);
}
}
}
My Action Post method where I want to receive the form:
[HttpPost]
public IActionResult AddPcPart(PcBuildAddViewModel viewModel)
{
return RedirectToAction("Add");
}
And finnaly my AJAX:
$('#AddPcForm').on('submit', function(event) {
var viewModel = $(this).serialize();
ajaxPost("/PCBuild/AddPcPart", viewModel);
event.preventDefault();
});
function ajaxPost(ul, dt) {
$.ajax({
type: "POST",
url: ul,
dataType: "json",
contentType: "application/json; charset=utf-8",
data: dt,
success: ajaxSucces,
error: function(result) {
console.log(result);
}
});
}
I hope that someone can help me. I've tried this without AJAX and it worked fine but when I call trough AJAX. I get a empty viewmodel or when I put [Frombody] in front of my parameter in the controller i get a null viewmodel.
Thanks to Stephen Muecke that posted the answer. The problem is that the contentType needs to be the default so I just removed the contentType parameter in my AJAX post. After that I removed the [FromBody] because that wasn't needed anymore.

Pass multiple Id's against multiple values in database

I'm working on a task that uses autocomplete textbox items containing names, stores in textbox or in listbox with their associated Id's(hidden) and inserted into the required table (only their related id's). I'm working on mvc 5 application. So far I've achieved to add value in listbox with names but not Id's. And trying to add the listbox values get stored in database. Below is my code.
Note:- I'm using partial view to display listbox when the button clicks. The current scenario is that it the listbox overwrites the first value when inserting second value.
StudentBatch.cs
public List<string> selectedids { get; set; }
public List<string> SelectedNames { get; set; }
Create.cshtml
<div class="form-group">
<div class="col-md-12">
#Html.EditorFor(model => model.StudentName, new { id = "StudentName" })
<input type="button" value="Add Text" id="addtypevalue" />
<div id="typevaluelist"></div>
</div>
</div>
<div id="new" style="display:none;">
<div class="typevalue">
<input type="text" name="typevalue" />
<button type="button" class="delete">Delete</button>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Add Students" class="btn btn-default" />
</div>
</div>
<script type="text/javascript">
$(document).ready(function () {
$("#StudentName").autocomplete({
//autocomplete: {
// delay: 0,
// minLength: 1,
source: function (request, response)
{
$.ajax({
url: "/Student/CreateStudent",
type: "POST",
dataType: "json",
data: { Prefix: request.term },
success: function(data) {
try {
response($.map(data,
function (item)
{
return { label: item.FirstName, value: item.FirstName };
}));
} catch (err) {
}
}
});
},
messages:
{
noResults: "jhh", results: "jhjh"
}
});
});
</script>
<script>
$('#addtypevalue').click(function () {
$(document).ready(function () {
var selValue = $('#StudentName').val();
$.ajax({
type: "GET",
url: '#Url.Action("GetListBox", "Student")',
dataType: "html",
data: { CourseId: selValue },
success: function (data) {
$("#partialDiv").html(data);
},
failure: function (data) {
alert('oops something went wrong');
}
});
});
});
</script>
GetListBox.cshtml
#model WebApplication1.Models.StudentBatch
#if (ViewBag.Value != null)
{
#Html.ListBoxFor(m => m.SelectedNames, new SelectList(Model.SelectedNames))
}
StudentController.cs
public PartialViewResult GetListBox(string CourseID)
{
Context.Student studCont = new Context.Student();
Models.StudentBatch student = new Models.StudentBatch();
student.SelectedNames = new List<string>();
student.SelectedNames.Add(CourseID);
ViewBag.Value = student;
return PartialView(student);
}

Unobtrusive client validation is not working when the form contains hidden input field

I have a model like:
public class Person
{
public int ID { get; set; }
[Required]
public string LastName { get; set; }
[Required]
public string FirstMidName { get; set; }
}
And the view:
#model ContosoUniversity.Models.Student
#using (Html.BeginForm("Edit", "Student", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.HiddenFor(model => model.ID)
<div
#Html.LabelFor(model => model.LastName, new { #class = "control-label col-md-2" })
#Html.EditorFor(model => model.LastName)
#Html.ValidationMessageFor(model => model.LastName)
</div>
<div >
#Html.LabelFor(model => model.FirstMidName, new { #class = "control-label col-md-2" })
#Html.EditorFor(model => model.FirstMidName)
#Html.ValidationMessageFor(model => model.FirstMidName)
</div>
<div>
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
}
The problem is that when I am rendering the view using Ajax Get using return PartialView("Edit", student); statement, the unobtrusive jQuery validation fails. The validation is working fine when I remove the hidden field #Html.HiddenFor(model => model.ID).
I have used below code to render the view using Ajax Get request:
function ShowEditPartialView(sender) {
$.ajax({
type: "GET",
url: "/Student/EditPartial",
data: {
id: courseid
},
async: false,
success: function (data) {
$("#EditCoursePartial").html(data);
///because the page is loaded with ajax, the validation rules are lost, we have to rebind them:
$('form').removeData('validator');
$('form').removeData('unobtrusiveValidation');
$.validator.unobtrusive.parse('form');
}
});
}
Any idea on how it will be resolved.

Resources