Object array in FormData passing 0 objects to controller - javascript

I'm making an ajax call to the controller passing the FormData(), which has an array of objects along with few other properties. In my controller, the list array which I'm passing seems to have 0 elements. Please help!
Script in cshtml view -
var _getFormDataToJson = function () {
var applyDetail = [];
$(_tb).find('tbody tr').each(function (i, v) {
var trans = {
effectiveDate: $(this).find('.effectiveDate').val(),
amount: $(this).find('.amount').val(),
empLeaveHdID: $('#tx-leaveHdID').val(),
//attachmentUrl: $(this).find('.leaveAttachment')[0].files[0]
}
applyDetail.push(trans);
});
var formObj = new FormData();
formObj.append('remark', $('#tx-remark').val());
formObj.append('leaveAppType', $('#hdnLeaveAppType').val());
formObj.append('applyDetail', applyDetail); //this collection has 0 items in controller
return formObj;
}
var _sumbitForm = function () {
var formData2 = _getFormDataToJson();
$.ajax({
url: '#Url.Action("ApplyLeave", "Leave")',
type: 'POST',
processData: false,
contentType: false,
data: formData2,
//data: { data: formData2 },
success: function (data) {
if (data.success) {
_myToastr.success(data.msg[0], true, function () {
location.reload();
});
$(_modal).modal('close');
}
else {
_myToastr.error(data.msg[0]);
}
},
complete: function () {
}
});
}
Controller -
[HttpPost]
public JsonResult ApplyLeave(Hr_LeaveApplyHd data)
{
foreach (var detail in data.applyDetail) //applyDetail count is 0 here
{
//to DO:
}
return new JsonResult();
}
EDIT:
Hr_LeaveApplyHd model -
public class Hr_LeaveApplyHd
{
public Hr_LeaveApplyHd()
{
applyDetail = new List<ApplyDetail>();
}
[Key]
public int applyID { get; set; }
public string remark { get; set; }
public virtual List<ApplyDetail> applyDetail { get; set; }
public LeaveAppType leaveAppType { get; set; }
}
applyDetail model -
public class ApplyDetail
{
[Key]
public int applyDetialID { get; set; }
public DateTime effectiveDate { get; set; }
public decimal amount { get; set; }
public int empLeaveHdID { get; set; }
}

You cannot append arrays and/or complex objects to FormData. You need to append name/value pairs for each property of ApplyDetail and for each item in the collection, and with indexers, for example
formObj .append('applyDetail[0].effectiveDate', '09/19/2017');
which you could do in your $.each loop, for example
var formObj = new FormData();
formObj.append('remark', $('#tx-remark').val());
formObj.append('leaveAppType', $('#hdnLeaveAppType').val());
$(_tb).find('tbody tr').each(function (i, v) {
var name = 'applyDetail[' + i + '].effectiveDate';
var value = $(this).find('.effectiveDate').val();
formObj.append(name, value);
... // ditto for other properties
});
However, if you have generated your form correctly using the strongly typed HtmlHelper methods, including generating the controls for the collection property using a for loop of EditorTemplate for typeof ApplyDetail so they have the correct name attributes to match your model, then all you need is
var formObj = new FormData($('form').get(0));
which will correctly serialize all the form controls

Related

fetching an Object from Action Item and displaying on View without Page refresh Using Ajax and Javascript

public class vendorData
{
public int VCode { get; set; }
public string currency { get; set; }
}
[HttpGet]
public IActionResult OnGetVendorCode(string VendorName)
{
var VendorMaster = _context.VendorMaster.ToList();
var VendorCodes = from O in VendorMaster where O.CompanyID == Company && O.VendorName == VendorName select O.VendorCode;
var currency= from O in VendorMaster where O.CompanyID == Company && O.VendorName == VendorName select O.Currency;
vendorData vendorData = new vendorData();
vendorData.VCode = VendorCodes.FirstOrDefault();
vendorData.currency = currency.FirstOrDefault();
return new JsonResult(vendorData);
}
function GetPOVendorCode(ID) {
$.ajax(
{
data: { VendorName: ID },
url: '/Purchase/POGenerals/Create/?handler=VendorCode',
type: 'GET',
success: function (data) {
const myJSON = JSON.stringify(data);
alert(myJSON.VCode);
}
});
}
How can I access each object item through my Ajax call? and save it in a variable so that I could use that on my page? Is there any other better way? I am using ASP razor pages and trying to update other text boxes of the purchase order when I select the vendor name
The response data is the correct object so that no need use JSON.stringify(data);.
Also the response data is camel case format.
In summary, just use data.vCode to get the value.

POST 500 error when sending JSON stringified javascript object to controller

I'm currently working on a ASP.net Web application with the MVC pattern. I have set up a page where people can add items to a gridstack section and drag them around (Gridstack is a plugin to create draggable boxes/objects). My goal is to send the final coordinates of these boxes to my controller:
function saveData() {
var pagePositions = [];
// Fill our array
$('.grid-stack-item.ui-draggable').each(function () {
var $this = $(this);
pagePositions.push({
x: $this.attr('data-gs-x'),
y: $this.attr('data-gs-y'),
w: $this.attr('data-gs-width'),
h: $this.attr('data-gs-height'),
content: $('.grid-stack-item-content', $this).html()
});
});
// Convert array to object
var pagePosData = toObject(pagePositions);
alert(pagePosData);
$.ajax({
type: "POST",
url: "savePage",
data: { positions: JSON.stringify(pagePosData) }
});
} function toObject(arr) {
var rv = {};
for (var i = 0; i < arr.length; ++i)
if (arr[i] !== undefined) rv[i] = arr[i];
return rv;
}
The code above fills the attributes of the given html elements and puts them into an array. I assumed, according to several topics on the internet, that sending the array was causing trouble so i inserted a function that converts the array to an javascript object (key value pairs). I send them to my controller with an AJAX call which results in a error code 500:
[HttpPost]
public string savePage(string positions)
{
//some code
var json = positions;
var test = "";
CreatePagemodelJson obj = new JavaScriptSerializer().Deserialize<CreatePagemodelJson>(positions.ToString());
//var jsonObject = JsonConvert.DeserializeObject<CreatePagemodel>(positionsJson.ToString());
return "";
}
I set up breakpoints inside the controller to read the value i get from the parameter positions, but it doesn't even get to that point. I tried setting up models for the Json file but the problem here is that the post calls return a dynamic json format.
Update:
I managed to get it working with below posts. With below structure, i get the results as an array according to my model.
function saveData() {
var pagePositions = [];
// Fill our array
$('.grid-stack-item.ui-draggable').each(function () {
var $this = $(this);
pagePositions.push({
x: $this.attr('data-gs-x'),
y: $this.attr('data-gs-y'),
w: $this.attr('data-gs-width'),
h: $this.attr('data-gs-height'),
content: $('.grid-stack-item-content', $this).html()
});
});
alert(pagePositions);
$.ajax({
type: "POST",
url: "savePage",
contentType: 'application/json',
data: JSON.stringify(pagePositions)
});
}
public class Position
{
public string x { get; set; }
public string y { get; set; }
public string w { get; set; }
public string h { get; set; }
public string content { get; set; }
}
[HttpPost]
public ActionResult savePage(IEnumerable<Position> positions)
{
//some code
return View("SomeView");
}
The parameter positions succesfully returns the array of pagePositions send with the post:
I tried sending the data without the JSON.stringify(pagePositions) and ContentType: 'application/json' option but i got a null return in my parameter on the controller.
There a number of things to point out here.
With your current question.
The data you are sending isn't a string. data: { positions: JSON.stringify(pagePosData) } is creating a JavaScript object with a property of positions whose value is the serialized version of your object.
You should be able to create a c# class and accept that as your controller methods parameter and get closer to the results you are expecting. That would look as follows:
public class Foo
{
public string Positions { get; set; }
}
public string savePage(Foo positions)
Alternatively you could update your method to get the request body as a string as shown in this SO answer
More importantly though, it would seem as though you came across some misinformation. There shouldn't be any issue passing an array back to your controller. Again, you will need a c# class that models your expected data type(s). You don't list those in your question, so it is hard to say for sure how you need to update your code, but I would suggest something more like the following:
function saveData() {
var pagePositions = [];
// Fill our array
$('.grid-stack-item.ui-draggable').each(function () {
var $this = $(this);
pagePositions.push({
x: $this.attr('data-gs-x'),
y: $this.attr('data-gs-y'),
w: $this.attr('data-gs-width'),
h: $this.attr('data-gs-height'),
content: $('.grid-stack-item-content', $this).html()
});
});
$.ajax({
type: "POST",
url: "savePage",
data: JSON.stringify(pagePositions),
contentType: "application/json"
});
}
public class Position
{
public int X { get; set; }
public int Y { get; set; }
public int W { get; set; }
public int H { get; set; }
public string Content { get; set; }
}
[HttpPost]
public string savePage(Position[] positions)
{
//some code
return "";
}
If this doesn't work, please provide more details about what doesn't work, what error you are receiving and what version of asp.net mvc you are using.

how to declare and update my class in my .cshtml file

I've create two classes for holding objects in my cshtml file, as below
public GroupBlock groupTemplate = new GroupBlock();
public RuleBlock ruleTemplate = new RuleBlock();
public class GroupBlock
{
public RuleBlock[] rules { get; set; }
}
public class RuleBlock
{
public string AndOr { get; set; }
public string dd1 { get; set; }
public string dd2 { get; set; }
public string dd3 { get; set; }
public string block { get; set; }
}
I now need to declare them in my cshtml file so that I can add data to them whenever a new line is created. My model file is declared as follows
#model Client.Web.Models.TaskViewModel
I've then tried to declare my two classes as
var rules = new #model.ruleTemplate;
var groups = new #model.groupTemplate;
This shows a syntax error, what am I missing?
I assume that GroupBlock and RuleBlock are nested class. How about this :
var rules = new TaskViewModel.RuleBlock() ;
var groups = new TaskViewModel.GroupBlock();
Trying to access my variables in my cshtml file was not working so I shifted the process to my Controller using the following code
$.ajax({
type: "GET",
cache: false,
data: {"id" : id , "idx" : ruleIndex},
url: "#Url.Action("UpdateSelectRule")",
dataType: "html",
success: function (result) {
$("#ajaxResult").html(result);
}
});
and accessed the variables from there by creating a 'new' class of my model.
ValidateTaskViewModel model = new validateTaskViewModel();
model.groupId = id;

How can I prevent passing in multiple parameters to controller?

Right now I have a form that contains 6 security questions and 6 security answers. I've been trying to refactor my code and I'm running into an interesting situation that I'm not sure on how to proceed.
Here's my view:
var RequestSecurityQuestions_Submit = function () {
ValidationAttribute.BlankValue(true);
var form = $('form#RequestSecurityQuestions');
$.validator.unobtrusive.parse(form);
var d = $('form#RequestSecurityQuestions').serialize();
SecurityQuestionsValid = true;
var inputs = $('form#RequestSecurityQuestions').find('input[data-val]');
$.each(inputs, function (index) {
var input = inputs[index];
if (!$(input).valid()) {
SecurityQuestionsValid = false;
}
});
var dataObject = {}, dropdowns = $("input.customdropdownlist");
for (var i = 0; i < 6; i++) {
dataObject['question' + i] = $(dropdowns[i]).data("kendoDropDownList").value()
}
for (var i = 1; i < 7; i++) {
dataObject['answer' + i] = $('#idAnswer' + i).val();
}
var dataToPass = JSON.stringify(dataObject);
if (SecurityQuestionsValid) {
$.ajax({
url: Url.getFullUrl('Account/RequestSecurityQuestions_Submit'),
type: 'Post',
data: { securityInfo: dataToPass },
dataType: 'json',
cache: false,
success: function (data) {
//Next Dialog
},
error: AjaxLog.HandleAjaxCallFail
});
}
return SecurityQuestionsValid;
}
I get a dataObject which contains all the values from my view and I want to pass it to the controller.
Currently this works:
[AllowAnonymous]
[HttpPost]
public ActionResult RequestSecurityQuestions_Submit(string answer1, string answer2, string answer3, string answer4, string answer5, string answer6, string question1, string question2, string question3, string question4, string question5, string question6)
{
SecurityQuestions securityQuestions = new SecurityQuestions();
if (!string.IsNullOrEmpty(answer1))
{
securityQuestions.ChallengeA1 = answer1;
}
if (!string.IsNullOrEmpty(answer2))
{
securityQuestions.ChallengeA2 = answer2;
}
if (!string.IsNullOrEmpty(answer3))
{
securityQuestions.ChallengeA3 = answer3;
}
//etc....
}
However, I am passing in 12 parameters to my controller which sounds like a no-no to me. Is there another way to pass in my data from my view to my controller without having to pass in 12 parameters?
EDIT:
New controller attempt:
/*Problem: securityInfo array looks like: ""{\"question0\":\"2\",\"question1\":\"3\",\"question2\":\"4\",\"question3\":\"5‌​\",\"question4\":\"7\",\"question5\":\"1\",\"answer1\":\"fgfg\",\"answer2\":\"fgf‌​gf\",\"answer3\":\"fgfg\",\"answer4\":\"fgfgfg\",\"answer5\":\"fgfg\",\"answer6\"‌​:\"fggf\"}"" */
[AllowAnonymous]
[HttpPost]
public ActionResult RequestSecurityQuestions_Submit(string[] securityInfo)
{
SecurityQuestions securityQuestions = new SecurityQuestions();
}
There are multiple ways to achieve this of course, the following is one of them. A better one would be to restructure your code as per other answers/comments.
// Creating your array
var dataObject = [],
dropdowns = $("input.customdropdownlist");
//Populate your array. [0-5] will be questions and [6-11] will be answers .
for (var i = 0; i < 6; i++) {
if (i < 6){
dataObject[i] = $(dropdowns[i]).data("kendoDropDownList").value()
}
else {
var d = i - 5;
dataObject[i] = $('#idAnswer' + d).val();
}
}
// Your AJAX call with contentType
$.ajax({
url: Url.getFullUrl('Account/RequestSecurityQuestions_Submit'),
type: 'Post',
data: JSON.Stringify(dataObject), //Change data format to JSON array, will be received as array in backend
contentType: "application/json",
cache: false,
success: function (data) {
//Next Dialog
},
error: AjaxLog.HandleAjaxCallFail
});
And simply receive the array in your backend
public ActionResult RequestSecurityQuestions_Submit(List<String> data)
{
//Your code here
}
Mate, Well, I don't understand why you have N parameters which has the same type of data--- that's really where the class should come for.
Short Answer will be you can create a Model which contains these parameters, then on your controller, just RequestSecurityQuestions_Submit(Model postedModel)
then access your parameters inside like postedModel.parameter1 ... In you ajax call , it looks like
$.ajax({
url: Url.getFullUrl('Account/RequestSecurityQuestions_Submit'),
type: 'Post',
data: {parameter1:'',parameter2:''...},
cache: false,
success: function (data) {
//Next Dialog
},
Multiple parameter(n>3) on any function is bad in theory and practice,
You can simplify all this by correctly using a model, binding to a model and posting back you model.
View models
public class SecurityAnswerVM
{
[Required(ErrorMessage="Please select a question")]
[Display(Name = "Question")]
public int? QuestionID { get; set; }
[Required(ErrorMessage = "Please enter an answer")]
public string Answer { get; set; }
}
public class SecurityLoginVM
{
public SelectList QuestionList { get; set; }
public List<SecurityAnswerVM> SelectedQuestions { get; set; }
}
Controller
[HttpGet]
public ActionResult Index()
{
SecurityLoginVM model = new SecurityLoginVM();
// Populate SelectedQuestions and QuestionList from the database
return View(model);
}
[HttpPost]
public ActionResult Index(SecurityLoginVM model)
{
// model.SelectedQuestions contains the 6 objects containing the QuestionID and the users Answer
....
}
EditorTemplate (/Views/Shared/EditorTemplates/SecurityAnswerVM.cshtml)
#model yourAssembly.SecurityAnswerVM
#Html.LabelFor(m => m.QuestionID)
#Html.DropDownListFor(m => m.QuestionID, (SelectList)ViewData["options"], "Please select", new { #class = "question" })
#Html.ValidationMessageFor(m => m.QuestionID)
#Html.LabelFor(m => m.Answer)
#Html.TextAreaFor(m => m.Answer)
#Html.ValidationMessageFor(m => m.Answer)
Main view
#model yourAssembly.SecurityLoginVM
#using(Html.BeginForm())
{
#Html.EditorFor(m => m.SelectedQuestions, new { options = Model.QuestionList })
<button id="save type="submit">Save</button> // or type="button" is posting via ajax
}
And if you want to use ajax to post the data
var url = '#Url.Action("Index")';
$('#save').click(function() {
$.post(url, $('form').serialize(), function(data) {
// Next Dialog
});
});
Far less code, strongly typed model binding, client and server side validation and all the other beneficial features of using MVC!
Why not doing something like this -
public class QA {
public int QId {get;set;}
public string Answer {get;set;}
}
[AllowAnonymous]
[HttpPost]
public ActionResult RequestSecurityQuestions_Submit(QA[] answers)
{
for (var qa in answers){
//do what ever you like
}
}
and then in js -
// Creating your array
var dataObject = [],
var dropdowns = $("input.customdropdownlist");
for (var i = 0; i < 6; i++) {
dataObject[i] = {
'QId': $(dropdowns[i]).data("kendoDropDownList").value(),
'Answer': dataObject[i] = $('#idAnswer' + i).val();
};
}
$.ajax({
url: Url.getFullUrl('Account/RequestSecurityQuestions_Submit'),
type: 'Post',
data: JSON.stringify(dataObject),
contentType: "application/json",
cache: false,
success: function (data) {
},
error: function(data){
}
});

JSON.parse for array of object

Server returns the array of object in JSON. It looks so:
{"d":"[
{\"Id\":1,\"IsGood\":true,\"name1\":\"name1dsres\",\"Name2\":\"name2fdsfd\",\"name3\": \"name3fdsgfd\",\"wasBorn\":\"\\/Date(284011000000)\\/\"},
{\"Id\":2,\"IsGood\":false,\"name1\":\"fdsfds\",\"name2\":\"gfd3im543\",\"name3\":\"3543gfdgfd\",\"WasBorned\":\"\\/Date(281486800000)\\/\"}
]"}
I need to parse using JSON.parse function. I'm doing this this way:
function myFunction(dataFromServer){
var parsedJSON = JSON.parse(dataFromServer.d);
for (var item in parsedJSON.d) {
// how do I get the fields of current item?
}
This code is not working, it returns undefined
for (var item in parsedJSON) {
alert(item.Id);
}
This works perfectly
function myFunction(dataFromServer){
var parsedJSON = JSON.parse(dataFromServer.d);
for (var i=0;i<parsedJSON.length;i++) {
alert(parsedJSON[i].Id);
}
}
But this doens't
function myFunction(dataFromServer){
var parsedJSON = JSON.parse(dataFromServer.d);
for (var item in parsedJSON) {
alert(item.Id);
}
}
You can just access them as you would any object:
var id = item.Id;
if (item.IsGood) { ... }
If you wish to enumerate them to use somehow, have a look at this SO question.
You can access them as you do oridinary javascript objects,
that is either as item.id or item['id']
class Program
{
static void Main(string[] args)
{
var jsonString = #"{
""data"": [
{
""uid"": ""100001648098091"",
""first_name"": ""Payal"",
""last_name"": ""Sinha"",
""sex"": ""female"",
""pic_big_with_logo"": ""https://m.ak.fbcdn.net/external.ak/safe_image.php?d=AQAi8VLrTMB-UUEs&bust=1&url=https%3A%2F%2Fscontent-a.xx.fbcdn.net%2Fhprofile-ash2%2Fv%2Ft1.0-1%2Fs200x200%2F10018_433988026666130_85247169_n.jpg%3Foh%3Dc2774db94dff4dc9f393070c9715ef65%26oe%3D552CF366&logo&v=5&w=200&h=150"",
""username"": ""payal.sinha.505"",
},
]
}";
dynamic userinfo = JValue.Parse(jsonString);
IList<FacebookUserDetail> userDeatils = new List<FacebookUserDetail>();
// 1st method
foreach (dynamic userinfoItr in userinfo.data)
{
FacebookUserDetail userdetail= userinfoItr.ToObject<FacebookUserDetail>();
userDeatils.Add(userdetail);
}
// 2nd Method
var userDeatils1 = JsonConvert.DeserializeObject<FacebookUserDetails>(jsonString);
}
}
public class FacebookUserDetail
{
public string username { get; set; }
//Password = EncryptionClass.Md5Hash(Guid.NewGuid().ToString()),
public string first_name { get; set; }
public string last_name { get; set; }
public string sex { get; set; }
public string pic_big_with_log { get; set; }
}
enter code here
public class FacebookUserDetails
{
public IList<FacebookUserDetail> data { get; set; }
}
}

Categories

Resources