How to post various custom data types using Ajax in MVC3? - ajax

I have this ViewModel to represent each Category and it's several Sub-Categories in my project:
public class Categories
{
//a simple string for the category name
[Required]
public string Cat_Name { get; set; }
//a list of strings for the sub-categories
public List<string> SubCat_Name { get; set; }
}
I pass this model to the view, and I use it to construct my form like this:
#using (Html.BeginForm("Category", "Admin", FormMethod.Post))
{
#Html.TextBoxFor(m => m.Name, new { #class = "Cat" })
#Html.TextBoxFor(m => m.SubName, new { #class = "Sub" })
#Html.TextBoxFor(m => m.SubName, new { #class = "Sub" })
#Html.TextBoxFor(m => m.SubName, new { #class = "Sub" })
#Html.TextBoxFor(m => m.SubName, new { #class = "Sub" })
<input type="button" value="Create New Category" name="Category" onclick="DoIt()" />
}
And as you see, the javascript function "DoIt()" is called by the click on the input button.
here's the function :
function DoIt() {
var stringArray = new Array();
//I put all of the sub-categories inside an array, to be like a list<string>
$(".Sub").each(function (index, value) {
stringArray[index] = this.value;
});
$.ajax({
url: '/Admin/Category',
type: "POST",
data: JSON.stringify($(".Cat").attr("value") , stringArray),
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function () { console.log("post done"); },
error: function () { }
});
}
As you can see, in the ajax method I'm trying to pass the "Category Name" $(".Cat").attr("value") and it's "Sub-Category Names" stringArray to the corresponding action method which requires Categories datatype I created as a viewmodel before. It looks like this:
public ActionResult Category(Categories CAT)
{
//Do something
return View();
}
The problem is the ajax method can't post two datatypes at once, or just that I don't know how to do it.
I also tried this :
var postdata = {
Name: $(".Cat").attr("value"),
SubName: stringArray
};
and put postdata inside the JSON.stringify() instead. But still nothing is passed to the action method.

I think you are very close.
Try this
var postdata = {
Cat_Name: $(".Cat").val(),
SubCat_Name: stringArray
};
&
$.ajax({
url: '/Admin/Category',
type: "POST",
data: JSON.stringify(CAT:postdata),
dataType: "json",
contentType: "application/json",
success: function () { console.log("post done"); },
error: function () { }
});

Try to send data formatted like this:
$.ajax({
url: '/Admin/Category',
type: "POST",
data: JSON.stringify({ Cat_Name: $(".Cat").val(), SubCat_Name: stringArray }),
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function () { console.log("post done"); },
error: function () { }
});

Related

Ajax post zero to controller

I'm trying to POST an int with Ajax to my controller
Js
<script>
function FillCity() {
var provinceId = $(provinces).val();
$.ajax({
url: "FillCity",
type: "POST",
data: { id: provinceId },
dataType: "json",
traditional: true,
contentType: 'application/json; charset=utf-8',
success: function (data) {
$("#cities").html(""); // clear before appending new list
$.each(data, function (i, city) {
$("#cities").append(
$('<option></option>').val(city.Id).html(city.Name));
});
}
});
}
</script>
code in my controller :
[HttpPost]
public ActionResult FillCity(int id)
{
var cities = _context.City.Where(c => c.ProvinceId == 5);
return Json(cities);
}
but it always post 0 as id, I tried digits instead of provinceId, but it rtills send 0
You should create an class that have a Id Property.
public class ProvinceIdDto
{
public int Id { get; set; }
}
replace int id with ProvinceIdDto model in action
[HttpPost]
public ActionResult FillCity(ProvinceIdDto model)
{
var cities = _context.City.Where(c => c.ProvinceId == model.Id);
return Json(cities);
}
replace { id: provinceId } with JSON.stringify({ Id: provinceId }),
<script>
function FillCity() {
var provinceId = $(provinces).val();
$.ajax({
url: "FillCity",
type: "POST",
data: JSON.stringify({ Id: provinceId }),
dataType: "json",
traditional: true,
contentType: 'application/json; charset=utf-8',
success: function (data) {
$("#cities").html(""); // clear before appending new list
$.each(data, function (i, city) {
$("#cities").append(
$('<option></option>').val(city.Id).html(city.Name));
});
}
});
}
</script>
Another options is you can replace HttpPost method with HttpGet and pass id to action like this.
Change type: "POST", to type: "GET",
<script>
function FillCity() {
var provinceId = $(provinces).val();
$.ajax({
url: "FillCity?id="+provinceId,//<-- NOTE THIS
type: "GET",//<-- NOTE THIS
dataType: "json",
traditional: true,
contentType: 'application/json; charset=utf-8',
success: function (data) {
$("#cities").html(""); // clear before appending new list
$.each(data, function (i, city) {
$("#cities").append(
$('<option></option>').val(city.Id).html(city.Name));
});
}
});
}
</script>
C#
[HttpGet]
public ActionResult FillCity(int id)
{
var cities = _context.City.Where(c => c.ProvinceId == id);
return Json(cities);
}
when you do { id: provinceId } you are creating an object with property id
in your controller you are just expecting an id. You will need to ether:
A pass it as a query parameter url: "FillCity?id=" + provinceId
B create an object to be parsed from the request body.
public class Payload {
public int Id {get;set;}
}
and use it like this
public ActionResult FillCity([FromBody] Payload payload)
Can you verify this statement has a value:
var provinceId = $(provinces).val();
It's possible that isn't finding what you are looking for, and because you have the type int as a parameter, it defaults it to "0".
You shouldn't need to change it to a GET and your MVC method is fine as is. You can see from JQuery's own sample it should work:
$.ajax({
method: "POST",
url: "some.php",
data: { name: "John", location: "Boston" }
})
.done(function( msg ) {
alert( "Data Saved: " + msg );
});
I think it might not be finding the input field successfully.

Model is not updating while submitting form AJAX Asp.Net MVC

I have got a MVCapplication where I am collecting details on form having KENDO controls, and along side I can update couple of dropdown controls using AJAX.
The problem I am facing currently that, when I submit the form with changed values in dropdown, and other controls doesn't updates the model, and it remains the same, even if the form shows the updated values, the model retains the old values.
I have tried all sorts of solutions and googled enough but no success. I am putting my code below to show what I am doing at the moment, anyone there, could look at it and guide me as what am I doing wrong.
VIEW
#(Html.Kendo().DropDownList()
.Name("ddlDateRange")
.DataTextField("Name")
.DataValueField("Id")
.BindTo(Model.ReportIntervals)
.Events(e =>
{
e.Change((#<text>
function()
{
var selectedDateRange = $("#ddlDateRange").data("kendoDropDownList").value();
$.ajax({
url: '#Url.Action("ChangeStartEndDates")',
type: 'POST',
data: JSON.stringify({ selectedDateRange: selectedDateRange }),
contentType: "application/json; charset=utf-8",
dataType: "json",
async: true,
success: function (data) {
$("#StartDate").data("kendoDatePicker").value(data.StartGamingDate);
$("#EndDate").data("kendoDatePicker").value(data.EndGamingDate);
},
error: function () { alert('Error in DateRange dropdownlist'); }
});
}
</text>));
})
)
#(Html.Kendo().DatePickerFor(model => model.StartGamingDate)
.Name("StartDate")
.Events(e =>
{
e.Change((#<text>
function()
{
var startDate = $("#StartDate").val();
var endDate = $("#EndDate").val();
$.ajax({
url: '#Url.Action("ChangeDateRangeName")',
type: 'POST',
data: JSON.stringify({ startDate: startDate, endDate: endDate }),
contentType: "application/json; charset=utf-8",
dataType: "json",
async: true,
success: function (data) {
$("#ddlDateRange").data("kendoDropDownList").text(data.ReportInterval.Name);
},
error: function () { alert('Error in StartDate DatePicker'); }
});
}
</text>));
}))
#(Html.Kendo().DatePickerFor(model => model.EndGamingDate)
.Name("EndDate")
.Events(e =>
{
e.Change((#<text>
function()
{
var startDate = $("#StartDate").val();
var endDate = $("#EndDate").val();
$.ajax({
url: '#Url.Action("ChangeDateRangeName")',
type: 'POST',
data: JSON.stringify({ startDate: startDate, endDate: endDate }),
contentType: "application/json; charset=utf-8",
dataType: "json",
async: true,
success: function (data) {
$("#ddlDateRange").data("kendoDropDownList").text(data.ReportInterval.Name);
},
error: function () { alert('Error in EndDate DatePicker'); }
});
}
</text>));
}))
CONTROLLER
**MODEL VALUES FORTHIS ACTION**
systemAuditReportViewModel.StartGamingDate = "01/01/2013";
systemAuditReportViewModel.EndGamingDate = "31/12/2013";
systemAuditReportViewModel.ReportInterval.Id = 30;
systemAuditReportViewModel.ReportInterval.Name = "Last Calender Year";
[HttpPost]
public JsonResult ChangeStartEndDates(int selectedDateRange)
{
SystemAuditReport systemAuditReportViewModel = new SystemAuditReport();
Nullable<DateTime> startGamingDate;
Nullable<DateTime> endGamingDate;
IG.General.Web.Model.ReportInterval reportInterval = new IG.General.Web.Model.ReportInterval();
reportInterval.Id = selectedDateRange;
IG.General.Web.Model.ReportIntervalFactory.GetDateRange(reportInterval, out startGamingDate, out endGamingDate);
systemAuditReportViewModel.StartGamingDate = startGamingDate;
systemAuditReportViewModel.EndGamingDate = endGamingDate;
return Json(systemAuditReportViewModel, JsonRequestBehavior.AllowGet);
}
**MODEL VALUES FOR THIS ACTION**
systemAuditReportViewModel.StartGamingDate = "27/03/2014";
systemAuditReportViewModel.EndGamingDate = "27/03/2014";
systemAuditReportViewModel.ReportInterval.Id = 2;
systemAuditReportViewModel.ReportInterval.Name = "Today";
[HttpPost]
public ActionResult GenerateReport(SystemAuditReport systemAuditReportViewModel)
{
var errors = ModelState.Values.SelectMany(v => v.Errors);
ReportContainer reportContainer = new ReportContainer();
if (ModelState.IsValid)
{
systemAuditReportViewModel.ReportPath = "/reports/";
//systemAuditReportViewModel.StartGamingDate = startDate;
//systemAuditReportViewModel.EndGamingDate = endDate;
this.CreateReport(systemAuditReportViewModel, out reportContainer);
}
return View(reportContainer);
}
We had struggled with this a bit as well. The binding is a little tricky with templates. You have to name the DropDownList the same as the model's bound index.
#model string
#(Html.Kendo().DropDownListFor(m => m)
.BindTo("#=Model.EntityClassId")
.DataTextField("Value")
.DataValueField("Id")
.Name("EntityClassId")
.OptionLabel(MyApp.Resources.Text.DamageTypeOptionLabel)
.AutoBind(true)
.DataSource( source => source
.Read( read=>read.Action("SomeMethod", "SomeController"))
.ServerFiltering(true)
)
.Events(events => events
.Select("onDamageTypeSelected")
.Change("onDamageTypeChanged")
.DataBound("onDamageTypeDatabound")
)
.HtmlAttributes(new{style="height:21px;vertical-align:center"})
)

MVC4 Ajax- Pass complete model to controller

I have my AJAX call
$.ajax({
type: 'post',
url: "/Store/LoadStoreIndex",
data: , //Entire Model Here!!
dataType: "text",
success: function (result) {
$('#Postback').html(result);
}
});
I need to send my entire model back to the controller, but after much searching can't find anything ... Can somebody show me what I need to be doing?
Controller Get Action
public ActionResult Index(YourModel model)
{
YourModel model = new YourModel();
return View(model);
}
View
#model YourModel
#using (Html.BeginForm("Index", "Home", FormMethod.Post, new { id = "form1" }))
{
#Html.TextBoxFor(x => x.EmailAddress)
#Html.TextBoxFor(x => x.Name)
...
}
Script
$(function () {
$('form').submit(function () {
if ($(this).valid()) {
$.ajax({
url: this.action,
type: this.method,
// you can post your model with this line
data: $(this).serialize(),
beforeSend: function () {
},
complete: function () {
},
success: function (result) {
},
error: function () {
}
});
}
return false;
});
});
Controller Post Action
[HttpPost]
public ActionResult Index(YourModel model)
{
return View();
}

To what mvc object do I bind this kind of javascript array?

I am populating an array with an [int,bool]:
$.each(ownedChecked, function (key, val) {
/*code to set id as int and paintedTrue as bool*/
ownedIDs.push([id,paintedTrue]);
});
I create a var that will be stringified:
var saveData = { OwnedListEntryIDs:ownedIDs };
//send data
$.ajax({
url: '/ListEntry/OwnedModels',
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify(saveData),
success: function (data) { alert('Update success: ' + data); },
failure: function (data) { alert('Update failed: ' + data); }
});
Here is the ViewModel:
public class OwnedPaintedSave
{
//collection contains a ListEntryID and a bool indicating whether it is painted or not
public Dictionary<int,bool> OwnedListEntryIDs { get; set; }
}
Once in the controller method, ModelState.Isvalid passes and code gets to the foreach loop, but models is always NULL:
[HttpPost]
public JsonResult OwnedModels(OwnedPaintedSave models)
{
if (ModelState.IsValid)
{
foreach (var id in models.OwnedListEntryIDs)
{ }
}
}
I tried setting traditional:true in the $.ajax method, but same issue. I'm guessing the Dictionary in the ViewModel is not what I need to bind to, but I'm not sure what it should be. Thanks for any help.
I gave the OwnedPaintedSave object two int[] properties, one for OwnedIDs and one for PaintedIDs.
I think the problem lies in your controller. You are passing var saveData = { OwnedListEntryIDs:ownedIDs }; (essentially a Dictionary<int, bool> - yes?) as your data but the parameter in the action result is of type OwnedPaintedSave
I think if you change your controller parameter to Dictionary<int, bool> ownedListEntryIDs and don't stringify the javascript object, the framework is clever enough to serialize and deserialize your object. So you would have this...
var saveData = { OwnedListEntryIDs:ownedIDs };
//send data
$.ajax({
url: '/ListEntry/OwnedModels',
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: saveData,
success: function (data) { alert('Update success: ' + data); },
failure: function (data) { alert('Update failed: ' + data); }
});
And then this in your controller...
[HttpPost]
public JsonResult OwnedModels(Dictionary<int, bool> ownedListEntryIDs)
{
if (ModelState.IsValid)
{
foreach (var id in ownedListEntryIDs)
{ }
}
}

Pass serialized form to Action and bind to model

I am trying to bind model received from Ajax call but that do not work. Maybe someone could help me?
I am calling ValidateFile Action using Ajax
$.ajax({
url: '#Url.Action("ValidateFile", "Converter")',
data: ({ file: fileName, formData: serializedForm }),
type: 'POST',
success: function (response) {
if (response.result) {
} else {
RemoveFile(fileName);
}
}
});
The Fiddler show such query
file=!!!SP+Design!!!.txt&formData%5BEmail%5D=tomas%40mydomain.com
I receive data in my Action with file parameter populated but formData.Email property is always Null
[HttpPost]
public JsonResult ValidateFile(string file, UploadOptionModel formData)
{
}
My UploadOptionModel model
namespace PC.Models
{
public class UploadOptionModel
{
public string Email { get; set; }
}
}
Form which I am trying to serialize
#model PC.Models.UploadOptionModel
#using (Html.BeginForm())
{
#Html.EditorFor(p => p.Email)
}
JS Serialization function
function serializeForm() {
var data = $("form").serializeArray();
var formData = {};
for (var i = 0; i < data.length; i++) {
formData[data[i].name] = data[i].value;
}
return formData;
}
You need to JSON encode the data and set the content type to JSON for the model binder to work with JSON. So try this:
$.ajax({
url: '#Url.Action("ValidateFile", "Converter")',
data: JSON.stringify({ file: fileName, formData: serializedForm }),
contentType: 'application/json',
type: 'POST',
success: function (response) {
if (response.result) {
} else {
RemoveFile(fileName);
}
}
});

Resources