I have a complex JSON Object like this:
var requestData = { __batchRequests: [ { __changeRequests: [
{ requestUri: "Customers", method: "POST", headers: { "Content-ID": "1" }, data: {
CustomerID: 400, CustomerName: "John"
} }
] } ] };
I am trying to do two things:
Declare this object but with the variable data empty
With a loop, add items dynamically to the data object,
How can I do it?
This isn't too complex an object. And it isn't JSON until it's converted into a string.
Right now, it's just plain-ol' JS objects and arrays.
Breaking that down into its elements might look like this:
var requestData = {};
requestData.__batchRequests = [];
requestData.__batchRequests[0] = {};
requestData.__batchRequests[0].__changeRequests = [];
requestData.__batchRequests[0].__changeRequests[0] = {};
requestData.__batchRequests[0].__changeRequests[0].requestUri = "Customers";
requestData.__batchRequests[0].__changeRequests[0].method = "POST";
requestData.__batchRequests[0].__changeRequests[0].headers = { "Content-ID" : "1" };
requestData.__batchRequests[0].__changeRequests[0].data = {};
Aside from the repeats, what do you see?
Personally, I see that __changeRequests[0] is an object as simple as:
var changeRequest = {
requestUri : "Customers",
method : "POST",
headers : { "Content-ID" : "1" },
data : {}
};
I also see that I can just push that onto my array of change requests:
requestData.__batchRequests[0].__changeRequests.push(changeRequest);
Right?
I also know that my changeRequest variable still points to the one that I just added to the array, and whatever I change on the object will show up as changed in the array's reference to the object, too:
changeRequest.data.CustomerName = "Bob";
changeRequest.data.CustomerID = "204";
requestData.__/*...*/changeRequests[0].data.CustomerName; // Bob
So how about writing yourself some helper-functions?
function extend (obj, additions) {
var key;
for (key in obj) { if (additions.hasOwnProperty(key)) {
obj[key] = additions[key];
}
}
function makeChangeRequest (url, method, headers, data) {
var request = {
requestUri : url,
method : method,
headers : {},
data : {}
};
extend(request.headers, headers);
extend(request.data, data);
return request;
}
function getBatch (num) { return requestData.__batchRequests[num]; }
var changeReq = makeChangeRequest("Customers",
"POST",
{ "Content-ID" : "1" },
{ CustomerName : "Bob", CustomerID : "2012" });
var batch = getBatch(0);
batch.__changeRequests.push(changeReq);
If you want to add more data to changeReq.data later:
extend(changeReq.data, { Address : "33 Nowhere Rd.", City : "Splitsville" });
For the first part of your question, you can initialize data with an empty associative array:
var requestData = { __batchRequests: [ { __changeRequests: [
{ requestUri: "Customers", method: "POST", headers: { "Content-ID": "1" }, data: {} }
] } ] };
This next part assumes, perhaps incorrectly, that you can use jQuery. It also assumes that you have an array containing all of the relevant key value pairs.
var customerDeetsArray =[{CustomerID: 400}, {CustomerName: "John"}];
for (var i in customerDeetsArray) {
requestData.data = $.extend(requestData.data, customerDeetsArray[i]);
}
See working example which makes use of console.debug:
http://jsfiddle.net/4Rh72/6/
Related
I passed the following object:
var myVar = { typeA: { option1: "one", option2: "two" } }
I want to be able to pull out the key typeA from the above structure.
This value can change each time so next time it could be typeB.
So I would like to know if there is any way to do that
I was able to solve using 'keys'
for a json example like this:
{
"1-0001": {
"name": "red",
"hex": "FF0000"
},
"1-0002": {
"name": "blue",
"hex": "0000FF"
},
"1-0003": {
"name": "green",
"hex": "008000"
}
}
I was able to use
Map<String, dynamic> decoded = json.decode(jsonString);
for (var colour in decoded.keys) {
print(colour); // prints 1-0001
print(decoded[colour]['name']); // prints red
print(decoded[colour]['hex']); // prints FF0000
}
To get all filenames you can use:
var data = ...
var filenames = [];
for(var i = 0; i < data.length; i++) {
var item = data[0]['files'];
var key = item.keys.first;
var filename = item[key]['filename'];
filenames.add(filename);
}
print(filenames);
You need to define a data type.
It is basically a map of (key value-pair) where key is changed as stated in question typeA or typeB
This Object has 2 properties option1 and option2 which is also strings.
Here is the sample code to construct model and how to use it
import 'package:TestDart/TestDart.dart' as TestDart;
main(List<String> arguments) {
var map = new Map<String, MyObject>();
map['typeA'] = new MyObject("one", "two");
map['typeB'] = new MyObject("one", "two");
print(map['typeA'].toString());
print(map['typeA'].toString());
}
class MyObject {
String _option1;
String _option2;
MyObject(this._option1, this._option2);
String get option2 => _option2;
String get option1 => _option1;
#override
String toString() {
return 'MyObject{option1: $_option1, option2: $_option2}';
}
}
Relevant answer
map.forEach((key, value) {
print("Key : ${key} value ${value}");
});
My json looks like this, it consists of objects and a few other properties:
let jsonobject = {
"one":{ id:'Peter'},
"two":{ id:'John'},
"three":{ id:'Ko'},
"id":1,
"name":'Jack'
}
I want to convert this to an array with lodash or something, the result would be:
[{ id:'Peter'},
{ id:'John'},
{ id:'Ko'}]
So I can use _.values(jsonobject) but how can I ditch the id and the name property which are obviously no objects? I want a compact solution and/or use lodash.
(1) Get all values for the outer object, (2) filter non object items.
_.filter(_.values(jsonobject), _.isObject)
Or alternatively the chained variant:
_(jsonobject).values().filter(_.isObject).value()
You can simply use filter with an isObject predicate to get the values.
var result = _.filter(jsonobject, _.isObject);
let jsonobject = {
"one": {
id: 'Peter'
},
"two": {
id: 'John'
},
"three": {
id: 'Ko'
},
"id": 1,
"name": 'Jack'
};
var result = _.filter(jsonobject, _.isObject);
console.log(result);
body > div { min-height: 100%; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>
You can loop over the key in your object and store those that are objects in an array.
var obj = {
"one":{ id:'Peter'},
"two":{ id:'John'},
"three":{ id:'Ko'},
"id":1,
"name":'Jack'
};
var arr = [];
for(var key in obj){
if(typeof obj[key] === 'object'){
arr.push(obj[key]);
}
}
console.log(arr);
We are working with a 3rd party grid (telerik kendo) that has paging/sorting/filtering built in. It will send the requests in a certain way when making the GET call and I'm trying to determine if there is a way to translate these requests to AutoQuery friendly requests.
Query string params
Sort Pattern:
sort[{0}][field] and sort[{0}][dir]
Filtering:
filter[filters][{0}][field]
filter[filters][{0}][operator]
filter[filters][{0}][value]
So this which is populated in the querystring:
filter[filters][0][field]
filter[filters][0][operator]
filter[filters][0][value]
would need to be translated to.
FieldName=1 // filter[filters][0][field]+filter[filters][0][operator]+filter[filters][0][value] in a nutshell (not exactly true)
Should I manipulate the querystring object in a plugin by removing the filters (or just adding the ones I need) ? Is there a better option here?
I'm not sure there is a clean way to do this on the kendo side either.
I will explain the two routes I'm going down, I hope to see a better answer.
First, I tried to modify the querystring in a request filter, but could not. I ended up having to run the autoqueries manually by getting the params and modifying them before calling AutoQuery.Execute. Something like this:
var requestparams = Request.ToAutoQueryParams();
var q = AutoQueryDb.CreateQuery(requestobject, requestparams);
AutoQueryDb.Execute(requestobject, q);
I wish there was a more global way to do this. The extension method just loops over all the querystring params and adds the ones that I need.
After doing the above work, I wasn't very happy with the result so I investigated doing it differently and ended up with the following:
Register the Kendo grid filter operations to their equivalent Service Stack auto query ones:
var aq = new AutoQueryFeature { MaxLimit = 100, EnableAutoQueryViewer=true };
aq.ImplicitConventions.Add("%neq", aq.ImplicitConventions["%NotEqualTo"]);
aq.ImplicitConventions.Add("%eq", "{Field} = {Value}");
Next, on the grid's read operation, we need to reformat the the querystring:
read: {
url: "/api/stuff?format=json&isGrid=true",
data: function (options) {
if (options.sort && options.sort.length > 0) {
options.OrderBy = (options.sort[0].dir == "desc" ? "-" : "") + options.sort[0].field;
}
if (options.filter && options.filter.filters.length > 0) {
for (var i = 0; i < options.filter.filters.length; i++) {
var f = options.filter.filters[i];
console.log(f);
options[f.field + f.operator] = f.value;
}
}
}
Now, the grid will send the operations in a Autoquery friendly manner.
I created an AutoQueryDataSource ts class that you may or may not find useful.
It's usage is along the lines of:
this.gridDataSource = AutoQueryKendoDataSource.getDefaultInstance<dtos.QueryDbSubclass, dtos.ListDefinition>('/api/autoQueryRoute', { orderByDesc: 'createdOn' });
export default class AutoQueryKendoDataSource<queryT extends dtos.QueryDb_1<T>, T> extends kendo.data.DataSource {
private constructor(options: kendo.data.DataSourceOptions = {}, public route?: string, public request?: queryT) {
super(options)
}
defer: ng.IDeferred<any>;
static exportToExcel(columns: kendo.ui.GridColumn[], dataSource: kendo.data.DataSource, filename: string) {
let rows = [{ cells: columns.map(d => { return { value: d.field }; }) }];
dataSource.fetch(function () {
var data = this.data();
for (var i = 0; i < data.length; i++) {
//push single row for every record
rows.push({
cells: _.map(columns, d => { return { value: data[i][d.field] } })
})
}
var workbook = new kendo.ooxml.Workbook({
sheets: [
{
columns: _.map(columns, d => { return { autoWidth: true } }),
// Title of the sheet
title: filename,
// Rows of the sheet
rows: rows
}
]
});
//save the file as Excel file with extension xlsx
kendo.saveAs({ dataURI: workbook.toDataURL(), fileName: filename });
})
}
static getDefaultInstance<queryT extends dtos.QueryDb_1<T>, T>(route: string, request: queryT, $q?: ng.IQService, model?: any) {
let sortInfo: {
orderBy?: string,
orderByDesc?: string,
skip?: number
} = {
};
let opts = {
transport: {
read: {
url: route,
dataType: 'json',
data: request
},
parameterMap: (data, type) => {
if (type == 'read') {
if (data.sort) {
data.sort.forEach((s: any) => {
if (s.field.indexOf('.') > -1) {
var arr = _.split(s.field, '.')
s.field = arr[arr.length - 1];
}
})
}//for autoquery to work, need only field names not entity names.
sortInfo = {
orderByDesc: _.join(_.map(_.filter(data.sort, (s: any) => s.dir == 'desc'), 'field'), ','),
orderBy: _.join(_.map(_.filter(data.sort, (s: any) => s.dir == 'asc'), 'field'), ','),
skip: 0
}
if (data.page)
sortInfo.skip = (data.page - 1) * data.pageSize,
_.extend(data, request);
//override sorting if done via grid
if (sortInfo.orderByDesc) {
(<any>data).orderByDesc = sortInfo.orderByDesc;
(<any>data).orderBy = null;
}
if (sortInfo.orderBy) {
(<any>data).orderBy = sortInfo.orderBy;
(<any>data).orderByDesc = null;
}
(<any>data).skip = sortInfo.skip;
return data;
}
return data;
},
},
requestStart: (e: kendo.data.DataSourceRequestStartEvent) => {
let ds = <AutoQueryKendoDataSource<queryT, T>>e.sender;
if ($q)
ds.defer = $q.defer();
},
requestEnd: (e: kendo.data.DataSourceRequestEndEvent) => {
new DatesToStringsService().convert(e.response);
let ds = <AutoQueryKendoDataSource<queryT, T>>e.sender;
if (ds.defer)
ds.defer.resolve();
},
schema: {
data: (response: dtos.QueryResponse<T>) => {
return response.results;
},
type: 'json',
total: 'total',
model: model
},
pageSize: request.take || 40,
page: 1,
serverPaging: true,
serverSorting: true
}
let ds = new AutoQueryKendoDataSource<queryT, T>(opts, route, request);
return ds;
}
}
I have a simple set of JSON data that I am pulling from a local file and loading into a datatable
Using YUI, how can I filter the response of this request to match only the data that is relevant to the request data?
EDIT: improper formatting on first post
YUI().use('aui-datatable', 'datatable-sort', 'aui-io-request', 'aui-tabview', 'datasource-io',
function(Y) {
var columns = [{
key : 'id',
sortable : true
}, {
key : 'name',
sortable : true
},{
key : 'price',
sortable : true
}];
var dataTable = new Y.DataTable({
columns : columns
}).render("#searchResultsTab");
var node = Y.one('#searchButton');
var criteria = document.getElementById("searchCriteria");
node.on(
'click', //on Search..
function(){
dataSource = new Y.DataSource.IO({source:'mydata.json'});
request = document.getElementById("searchBox").value;
dataSource.sendRequest({
on: {
success: function(e){
var response = e.data.responseText;
jdata = Y.JSON.parse(response);
dataTable.set('data', jdata.info); //setting table data to json response
},
failure: function(e){
alert(e.error.message);
}
}
});
}
);
new Y.TabView(
{
srcNode: '#searchResultsContainer'
}
).render();
});
mydata.json
{"info" : [
{"id": 1,"name": "A green door","price": 12.50 },
{"id": 2,"name": "A blue door","price": 10.50 },
{"id": 3,"name": "A red door","price": 8.50 }
}
In your on success method filter your response data before setting the datatable data source. Here is an example of model list filtering: http://yuilibrary.com/yui/docs/model-list/#filtering-models
I have multiple json Objects
json1 = [
{'category_id':1,'name':'test1' },
{'category_id':1,'name':'test2' },
{'category_id':1,'name':'test3' },
{'category_id':2,'name':'test2' },
{'category_id':3,'name':'test1' }
];
json2 = [{'category_id':1,'type':'test1'}];
json3 = [
{'category_id':1,'color':'black'},
{'category_id':2,'color':'black'},
{'category_id':3,'color':'white'}
];
I am expecting output like this
final = [
{'category_id':1,'name':'test1','type':'test`','color':'black' },
{'category_id':1,'name':'test2','type':'test`','color':'black' },
{'category_id':1,'name':'test3','type':'test`','color':'black' },
{'category_id':2,'name':'test2','color':'black' },
{'category_id':3,'name':'test1','color':'white' }
];
As i have long json object. Looping is good idea or not ? Does there is any inbuilt function for doing the same.
Using underscore you can achieve it via:
Demo Fiddle
var jsons = [json1, json2, json3];
var final = {};
// merge all data
_.each(jsons, function (jsonArr) {
_.each(jsonArr, function (json) {
final[json.category_id] = _.extend({}, final[json.category_id], json);
});
});
// map it back onto json1
var finalArr = _.map(json1, function (json) {
return final[json.category_id];
});
console.log(finalArr);
Final value of finalArr:
Here is how you can do the same in plain javascript. :)
var final = {};
var jsons = [json1, json2, json3];
for(var i=0;i<jsons.length;i++){
final[i]=jsons[i];
}
Fiddle
EDIT:
Well, you will have to do it programmatically!