I have a controller in MVC, and return JSON like below:
public JsonResult getData()
{
var data = new[]{
new
{
x = 10,
y = 20,
name = "Jim",
},
new
{
x = 11,
y = 21,
name = "Tom",
}
};
return Json(data, JsonRequestBehavior.AllowGet);
}
And I have AJAX request like below:
$.ajax({
type: "GET",
url: "https://localhost:44361/home/getdata",
dataType: "json",
success: function (result) {
return result;
},
error: function (response) {
return "faut";
}
});
I want to convert the JSON result to below Array
var arr = [
['x','y','name'],
[10,20,'Jim'],
[11,21,'Tom']
];
Try this code:
const arr = [Object.keys(result[0])]
.concat(result.map(({x, y, name}) => [x, y, name]))
Alternative, cross-browser solution:
const arr = [Object.keys(result[0])]
.concat(result.map(function(obj) {
return [obj.x, obj.y, obj.name]
}))
You can try something like this.
var mainArr = [['x', 'y', 'name']];
for(var i = 0; i < result.length; i++){
var arr = [];
arr.push(result[i].x);
arr.push(result[i].y);
arr.push(result[i].name);
mainArr.push(arr);
}
console.log(mainArr);
Related
After getting two integer upon the ajax request has been completed, this.N and this.M are not getting set by storeDims() even if the dims has correctly been decoded. So it seems that I cannot acces this.N and this.M declared in the constructor.
This is the code
class MapModel {
constructor() {
this.N; // need to initialize this after an ajax call
this.M;
this.seats = new Array();
this.remote_seats = new Array();
}
init(callback) {
let _this = this;
$.when(
_this.getDims(),
_this.getSeats(),
).then(this.initMap(callback))
}
initMap(callback) {
console.log(this.N); // prints undefined
console.log(this.M); // this as well
callback(this.N, this.M, this.seats);
}
getDims() {
let _this = this;
$.ajax({
url: 'src/php/data.php',
type: 'POST',
data: {action: 'getDims'},
success: function (result) {
let dims = JSON.parse(result); // dims[0] = 10, dims[1] = 6
_this.storeDims(dims);
}
});
}
storeDims(dims) {
console.log(dims);
this.N = parseInt(dims[0]);
this.M = parseInt(dims[1]);
console.log(this.N);
console.log(this.M);
}
getSeats() {
let _this = this;
$.ajax({
url: 'src/php/data.php',
type: 'POST',
data: {action: 'getSeats'},
success: function (result) {
let seats = JSON.parse(result);
_this.storeSeats(seats);
}
});
}
storeSeats(seats) {
this.remote_seats = seats;
console.log(this.remote_seats);
}
}
You need to return the ajax promises from the getDms and getSeats functions
getDims() {
let _this = this;
return $.ajax({
url: 'src/php/data.php',
type: 'POST',
data: {action: 'getDims'},
success: function (result) {
let dims = JSON.parse(result); // dims[0] = 10, dims[1] = 6
_this.storeDims(dims);
}
});
}
you can even pass the values directly to the initMap
init(callback) {
let _this = this;
$.when(
_this.getDims(),
_this.getSeats()
).then(function(dims,seats) {_this.initMap(dims,seats,callback)})
}
initMap(dimsRaw,seatsRaw, callback) {
let dims = JSON.parse(dimsRaw);
console.log(dims[0]);
console.log(dims[1]);
callback(dims[0], dims[1], this.seats);
}
The init promise callback is being called on the chain declaration, try adding a function wrapper:
init(callback) {
let _this = this;
$.when(
_this.getDims(),
).then(function() {_this.initMap(callback)})
}
I have a model created in javascript as follows
function Vehicle() {
this.type = 'Vehicle';
this.data = {
VehicleKey: null
}
};
I have a similar model created in c# as follows
public class Vehicle
{
public string VehicleKey { get; set; }
}
Now I am building an array of VehicleKeys in javascript as follows
function GetVehicleDetails(inputarray) {
var vehicleKeys = [];
for (var i = 0; i < inputarray.length; i++) {
var vehicleObject = new Vehicle();
vehicleObject.data.VehicleKey = inputarray[i].VehicleKey ? inputarray[i].VehicleKey : null;
vehicleKey.push(vehicleObject.data);
}
return vehicleKeys ;
}
I am calling the $.post(url, data) as follows
var objectToSend = GetVehicleDetails(selectedVehicles);
var data = JSON.stringify({
'vehicles': objectToSend
});
$.post(url, data)
.done(function (result) {
if (result) {
download(result, 'VehicleReport.xlsx', { type: 'application/octet-stream' });
console.log("Report created successfully");
}
else {
console.log("Error creating report");
}
}).fail(function (error) {
console.log("Error creating report.");
});
The MVC Controller has a method to accept Vehicles with multiple VehicleKeys coming from javascript
public byte[] CreateVehicleReport(List<Vehicle> vehicles)
{
//Generation of report and pass it back to javascript
}
Here I am able to submit the data in javascript as 10 and 11 for Vehicles but when it catches the c#, the count is coming as 0.
Any help would be greatly appreciated.
$.post is not posted Content-Type json data so you need to use $.ajax
function GetVehicleDetails(inputarray) {
var vehicleKeys = [];
for (var i = 0; i < inputarray.length; i++) {
var vehicleObject = {}; // Set Object
vehicleObject.VehicleKey = inputarray[i].VehicleKey ? inputarray[i].VehicleKey : null;
vehicleKeys.push(vehicleObject);
}
return vehicleKeys;
}
var objectToSend = GetVehicleDetails(selectedVehicles);
$.ajax({ type: 'POST',
url: url,
data: JSON.stringify(objectToSend),
contentType: "application/json",
dataType: 'json',
success: function (data) {
alert('data: ' + data);
},
}).done(function () {
if (result) {
console.log("Report created successfully");
}
else {
console.log("Error creating report");
}
}).fail(function () {
console.log("Error creating report.");
});
C# Method
[HttpPost("CreateVehicleReport")]
public byte[] CreateVehicleReport([FromBody]List<Vehicle> vehicles)
{
return null;
//Generation of report and pass it back to javascript
}
I used a similar approach once but with ajax and it went like this:
fill your array directly with the properties inside your class as object { } make sure the names are exactly the same:
function GetVehicleDetails(inputarray) {
var data_Temp = [];
for (var i = 0; i < inputarray.length; i++) {
var _vehiclekey = inputarray[i].VehicleKey ? inputarray[i].VehicleKey : null;
data_Temp.push({ VehicleKey : _vehiclekey });
});
return data_Temp;
}
var objectToSend = GetVehicleDetails(selectedVehicles);
var JsonData = JSON.stringify({ vehicles: objectToSend });
$.ajax({
type: "POST",
contentType: "application/json",
url: "/controllerName/actionName", //in asp.net using mvc ActionResult
datatype: 'json',
data: JsonData,
success: function (response) {
},
error: function (response) {
console.log(response);
}
});
And the ActionResult in the controller should look like this:
[HttpPost]
public ActionResult Create(List<Vehicle> vehicles)
{
//do whatever you want with the class data
}
I don't know if this is helpful for you but this always works for me and i hope it helps.
I have an $.ajax function on my page to populate a facility dropdownlist based on a service type selection. If I change my service type selection back and forth between two options, randomly the values in the facility dropdownlist will remain the same and not change. Is there a way to prevent this? Am I doing something wrong?
Javascript
function hydrateFacilityDropDownList() {
var hiddenserviceTypeID = document.getElementById('<%=serviceTypeID.ClientID%>');
var clientContractID = document.getElementById('<%=clientContractID.ClientID%>').value;
var serviceDate = document.getElementById('<%=selectedServiceDate.ClientID%>').value;
var tableName = "resultTable";
$.ajax({
type: 'POST',
beforeSend: function () {
},
url: '<%= ResolveUrl("AddEditService.aspx/HydrateFacilityDropDownList") %>',
data: JSON.stringify({ serviceTypeID: TryParseInt(hiddenserviceTypeID.value, 0), clientContractID: TryParseInt(clientContractID, 0), serviceDate: serviceDate, tableName: tableName }),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data) {
a(data);
}
,error: function () {
alert('HydrateFacilityDropDownList error');
}
, complete: function () {
}
});
}
function a(data) {
var facilityDropDownList = $get('<%=servicesFormView.FindControl("facilityDropDownList").ClientID%>');
var selectedFacilityID = $get('<%= selectedFacilityID.ClientID%>').value;
var tableName = "resultTable";
if (facilityDropDownList.value != "") {
selectedFacilityID = facilityDropDownList.value;
}
$(facilityDropDownList).empty();
$(facilityDropDownList).prepend($('<option />', { value: "", text: "", selected: "selected" }));
$(data.d).find(tableName).each(function () {
var OptionValue = $(this).find('OptionValue').text();
var OptionText = $(this).find('OptionText').text();
var option = $("<option>" + OptionText + "</option>");
option.attr("value", OptionValue);
$(facilityDropDownList).append(option);
});
if ($(facilityDropDownList)[0].options.length > 1) {
if ($(facilityDropDownList)[0].options[1].text == "In Home") {
$(facilityDropDownList)[0].selectedIndex = 1;
}
}
if (TryParseInt(selectedFacilityID, 0) > 0) {
$(facilityDropDownList)[0].value = selectedFacilityID;
}
facilityDropDownList_OnChange();
}
Code Behind
[WebMethod]
public static string HydrateFacilityDropDownList(int serviceTypeID, int clientContractID, DateTime serviceDate, string tableName)
{
List<PackageAndServiceItemContent> svcItems = ServiceItemContents;
List<Facility> facilities = Facility.GetAllFacilities().ToList();
if (svcItems != null)
{
// Filter results
if (svcItems.Any(si => si.RequireFacilitySelection))
{
facilities = facilities.Where(f => f.FacilityTypeID > 0).ToList();
}
else
{
facilities = facilities.Where(f => f.FacilityTypeID == 0).ToList();
}
if (serviceTypeID == 0)
{
facilities.Clear();
}
}
return ConvertToXMLForDropDownList(tableName, facilities);
}
public static string ConvertToXMLForDropDownList<T>(string tableName, T genList)
{
// Create dummy table
DataTable dt = new DataTable(tableName);
dt.Columns.Add("OptionValue");
dt.Columns.Add("OptionText");
// Hydrate dummy table with filtered results
if (genList is List<Facility>)
{
foreach (Facility facility in genList as List<Facility>)
{
dt.Rows.Add(Convert.ToString(facility.ID), facility.FacilityName);
}
}
if (genList is List<EmployeeIDAndName>)
{
foreach (EmployeeIDAndName employeeIdAndName in genList as List<EmployeeIDAndName>)
{
dt.Rows.Add(Convert.ToString(employeeIdAndName.EmployeeID), employeeIdAndName.EmployeeName);
}
}
// Convert results to string to be parsed in jquery
string result;
using (StringWriter sw = new StringWriter())
{
dt.WriteXml(sw);
result = sw.ToString();
}
return result;
}
$get return XHR object not the return value of the success call and $get function isn't synchronous so you should wait for success and check data returned from the call
these two lines do something different than what you expect
var facilityDropDownList = $get('<%=servicesFormView.FindControl("facilityDropDownList").ClientID%>');
var selectedFacilityID = $get('<%= selectedFacilityID.ClientID%>').value;
change to something similar to this
var facilityDropDownList;
$.ajax({
url: '<%=servicesFormView.FindControl("facilityDropDownList").ClientID%>',
type: 'get',
dataType: 'html',
async: false,
success: function(data) {
facilityDropDownList= data;
}
});
I always use querystring to parse data posted by client. But this is the first time I am posting an array, and I'm having same issue.
client side:
$.ajax({
url: 'myurl',
type: "POST",
data: {ids: ["str1","str2","str3"]},
success: function (msg) {
location.reload();
},
error: function (msg) {
alert("ServerError");
},
cache: false,
});
server side:
var body='';
req.on('data', function(chunk) {
body += chunk.toString();
});
req.on('end', function() {
var parsedbody = querystring.parse(body);
console.log(parsedbody);// {'ids[]':["str1","str2","str3"]}
My problem? Well, first note the comment: the key is ids[] intead of simply ids. So strange and annoyng. And the big problem: if I pass an array with one string like this:
data of ajax request--> data: { ids: ["str1"] }
the console.log becomes
console.log(parsedbody);// {'ids[]':"str1"}
console.log(parsedbody['ids[]'].length);// 4 (instead of 1)
As you can see my array become a string and this is a problem.
You could just easily create your own wrapper around querystring.parse(). Example:
var qs = require('querystring');
function parseQS(str) {
var result = qs.parse(str),
keys = Object.keys(result);
for (var i = 0, len = keys.length, key, newKey; i < len; ++i) {
key = keys[i];
if (key.slice(-2) === '[]') {
newKey = key.slice(0, -2);
if (!Array.isArray(result[key]))
result[newKey] = [ result[key] ];
else
result[newKey] = result[key];
delete result[key];
}
}
return result;
}
console.dir(parseQS('foo[]=bar&baz=bla&quux[]=123&quux[]=456'));
// outputs:
// { baz: 'bla',
// foo: [ 'bar' ],
// quux: [ '123', '456' ] }
The following code works great with a hardcoded array (initialData1), however I need to use jquery .ajax (initialData) to initialize the model and when I do the model shows empty:
$(function () {
function wiTemplateInit(winame, description) {
this.WIName = winame
this.WIDescription = description
}
var initialData = new Array;
var initialData1 = [
{ WIName: "WI1", WIDescription: "WIDescription1" },
{ WIName: "WI1", WIDescription: "WIDescription1" },
{ WIName: "WI1", WIDescription: "WIDescription1" },
];
console.log('gridrows:', initialData1);
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
dataType: "json",
data: "{UserKey: '10'}",
url: "WIWeb.asmx/GetTemplates",
success: function (data) {
for (var i = 0; i < data.d.length; i++) {
initialData.push(new wiTemplateInit(data.d[i].WiName,data.d[i].Description));
}
//console.log('gridrows:', initialData);
console.log('gridrows:', initialData);
}
});
var viewModel = function (iData) {
this.wiTemplates = ko.observableArray(iData);
};
ko.applyBindings(new viewModel(initialData));
});
I have been trying to work from the examples on the knockoutjs website, however most all the examples show hardcoded data being passed to the view model.
make sure your "WIWeb.asmx/GetTemplates" returns json array of objects with exact structure {WIName : '',WIDescription :''}
and try using something like this
function wiTemplateInit(winame, description)
{
var self = this;
self.WIName = winame;
self.WIDescription = description;
}
function ViewModel()
{
var self = this;
self.wiTemplates = ko.observableArray();
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
dataType: "json",
data: "{UserKey: '10'}",
url: "WIWeb.asmx/GetTemplates",
success: function (data)
{
var mappedTemplates = $.map(allData, function (item) { return new wiTemplateInit(item.WiName, item.Description) });
self.wiTemplates(mappedTemplates);
}
});
}
var vm = new ViewModel();
ko.applyBindings(vm);
If you show us your browser log we can say more about your problem ( Especially post and response ). I prepared you a simple example to show how you can load data with ajax , bind template , manipulate them with actions and save it.
Hope this'll help to fix your issue : http://jsfiddle.net/gurkavcu/KbrHX/
Summary :
// This is our item model
function Item(id, name) {
this.id = ko.observable(id);
this.name = ko.observable(name);
}
// Initial Data . This will send to server and echo back us again
var data = [new Item(1, 'One'),
new Item(2, 'Two'),
new Item(3, 'Three'),
new Item(4, 'Four'),
new Item(5, 'Five')]
// This is a sub model. You can encapsulate your items in this and write actions in it
var ListModel = function() {
var self = this;
this.items = ko.observableArray();
this.remove = function(data, parent) {
self.items.remove(data);
};
this.add = function() {
self.items.push(new Item(6, "Six"));
};
this.test = function(data, e) {
console.log(data);
console.log(data.name());
};
this.save = function() {
console.log(ko.mapping.toJSON(self.items));
};
}
// Here our viewModel only contains an empty listModel
function ViewModel() {
this.listModel = new ListModel();
};
var viewModel = new ViewModel();
$(function() {
$.post("/echo/json/", {
// Data send to server and echo back
json: $.toJSON(ko.mapping.toJS(data))
}, function(data) {
// Used mapping plugin to bind server result into listModel
// I suspect that your server result may contain JSON string then
// just change your code into this
// viewModel.listModel.items = ko.mapping.fromJSON(data);
viewModel.listModel.items = ko.mapping.fromJS(data);
ko.applyBindings(viewModel);
});
})