Serialize complex object with nested array and objects to build query params - javascript

Example of complex object which i want to serialize, so I can use it in url as query param
var query = {
"page": {
"number": 1,
"size": 50
},
"sort": "engagement_total",
"sort_direction": "asc",
"filters": {
"engagement_total": {
"type": "range",
"value": [
21,
46
]
}
}
}
JSON.stringify(query)
result with stringify
'{"page":{"number":1,"size":50},"sort":"engagement_total","sort_direction":"asc","filters":{"engagement_total":{"type":"range","value":[21,46]}}}'
Desired result
filters%5Bengagement_total%5D%5Btype%5D=range&filters%5Bengagement_total%5D%5Bvalue%5D%5B%5D=21&filters%5Bengagement_total%5D%5Bvalue%5D%5B%5D=46&page%5Bnumber%5D=1&page%5Bsize%5D=50&sort=engagement_total&sort_direction=asc

let obj = {
"page": {
"number": 1,
"size": 50
},
"sort": "engagement_total",
"sort_direction": "asc",
"filters": {
"engagement_total": {
"type": "range",
"value": [
21,
46
]
}
}
}
var flattenObj = function(data) {
var result = {};
function recurse(cur, prop) {
if (Object(cur) !== cur) {
result[prop] = cur;
} else if (Array.isArray(cur)) {
for (var i = 0, l = cur.length; i < l; i++)
recurse(cur[i], prop + "[" + i + "]");
if (l == 0)
result[prop] = [];
} else {
var isEmpty = true;
for (var p in cur) {
isEmpty = false;
recurse(cur[p], prop ? prop + "[" + p + "]" : p);
}
if (isEmpty && prop)
result[prop] = {};
}
}
recurse(data, "");
return result;
};
let output = flattenObj(obj);
let url = Object.entries(output).map(elem => (elem[0].replace(/\[[0-9]+\]/, '[]') + "=" + elem[1])).join("&")
console.log("url:", url)
console.log("encodeURI:", encodeURI(url))

Related

Getting bug in recursive functions?

I am using an array with nested object of array. Assigning the values in array's values according to input line index, values are passed into the array's indexed value. I have checked the condition that if in array object is there, it converts it into array and call the recursive function and it calls recursion until the object's array's value is full but don't know why it is not working properly. Please help me in this bug
(function($) {
var xmlOutput = document.querySelector(".xmlOutput");
let templateStore = [];
let preservedEntriesValue = [];
let selectedTemplate = [];
function generateDOMDropdown(selectedID) {
let optionTemplate = templateStore.map(function(entry) {
return `<option value="${
entry.id
}" ${entry.id === selectedID ? "selected" : ""}>${entry.name}</option>`;
});
$("#select").html(optionTemplate);
}
function processEntries(entries) {
let output = "";
for (const entry of entries) {
output += entry;
}
return output;
}
function parseJSONToXML(input) {
const domStructure = input.entriesValue.map(function(tagObj) {
if (typeof tagObj === "string") {
return `<${tagObj}></${tagObj}>`;
} else if (Array.isArray(tagObj)) {
if (tagObj.length > 1) {
return `<${tagObj[0]}>${tagObj[1]}</${tagObj[0]}>`;
} else if (tagObj.length == 1) {
return `<${tagObj[0]}></${tagObj[0]}>`;
}
} else {
const outerTag = Object.keys(tagObj).pop();
const innerDOM = parseJSONToXML({ entriesValue: tagObj[outerTag] });
return `<${outerTag}>${processEntries(innerDOM)}</${outerTag}>`;
}
});
return domStructure;
}
function preFillSelected() {
const root = selectedTemplate.root;
const domStructure = parseJSONToXML(selectedTemplate);
xmlOutput.innerText = vkbeautify.xml(
`<?xml version="1.0" encoding="UTF-8"?><${root}>${processEntries(
domStructure
)}</${root}>`,
5
);
}
$.ajax({
type: "get",
url: window.location.origin + "/templates.json",
success: function(data) {
templateStore = data;
if (data.length > 0) {
selectedTemplate = data[0];
generateDOMDropdown(selectedTemplate.id);
preservedEntriesValue = selectedTemplate.entriesValue;
preFillSelected();
$("#select")
.off("change")
.on("change", function() {
selectedTemplate = templateStore[$("#select").val()];
preservedEntriesValue = selectedTemplate.entriesValue;
preFillSelected();
window.template = selectedTemplate;
});
}
}
});
function generateValueJSON(
template,
lines,
inputLen,
templateLen,
flatLen,
cidx
) {
cidx = cidx || 0;
// console.log('Entry', lines, template, cidx);
return Array.from(template.entriesValue.entries()).map(([idx, entry]) => {
console.log("Lines", lines);
if (idx < lines.length) {
if (Array.isArray(entry)) {
return [entry[0], lines[idx]];
} else if (typeof entry === "object") {
// debugger;
const outerTag = Object.keys(entry).pop();
const innerLength = entry[outerTag].length;
if (cidx === 0) cidx = idx;
const outerIdx = cidx + innerLength;
// console.log((flatLen - templateLen - inputLen));
// console.log({ flatLen, templateLen, inputLen, outerIdx, cidx, idx });
const innerObj = generateValueJSON(
{ entriesValue: entry[outerTag] },
lines.slice(idx, outerIdx),
inputLen,
templateLen,
flatLen,
idx
);
// cidx = 0;
entry[outerTag] = innerObj;
return entry;
}
return [entry, lines[idx]];
}
return entry;
});
}
function mapLength(template) {
return template.entriesValue
.map((entry) => {
return typeof entry === "object"
? [Object.keys(entry), Object.values(entry)]
: entry;
})
.flat(3).length;
}
$("#txtInput").on("keyup", function() {
const lines = $(this)
.val()
.split("\n\n")
.map((v) => v.trim().replace(/\n/g, "<br/>"));
// console.log(preservedEntriesValue);
selectedTemplate.entriesValue = preservedEntriesValue;
templateLength = mapLength(selectedTemplate);
const newEntriesValue = generateValueJSON(
selectedTemplate,
lines,
lines.length,
selectedTemplate.entriesValue.length,
templateLength
);
// console.log(newEntriesValue);
selectedTemplate.entriesValue = newEntriesValue;
preFillSelected();
});
})(window.jQuery, Node);
//here is the data array
[{
"id": "1",
"name": "Template Name 2",
"root": "media",
"entriesValue": [
"mediaid",
"category",
"provider",
"date",
"caption_photo_1",
{
"image": [
"imageid",
"type",
"width",
"hfive"
]
},
{
"video": [
"name",
"type",
"bitrate",
"size",
"width",
"hfive",
"headline",
"summary"
]
}
]
},
{
"id": "0",
"name": "Template Name 1",
"root": "article",
"entriesValue": [
"author",
"headline",
"cats",
"subcats",
"image",
"video",
"tags",
"summary",
"content"
]
},
{
"id": "2",
"name": "Template Name 3",
"root": "article",
"entriesValue": [
"author",
"headline",
"cats",
"subcats",
"image",
"video",
"summary",
"content",
"keyword"
]
},
{
"id": "3",
"name": "Template Name 4",
"root": "root",
"entriesValue": [
"description",
"title",
"languageId",
"categoryIds"
]
}
]
At first input it work properly but in second input it passes the value in in both object
<image>
<imageid>Correct</imageid>
<type>bug</type>
<width>bug</width>
<hfive></hfive>``
</image>
<video>
<name>bug</name>
<type>bug</type>
<bitrate></bitrate>
<size></size>
<width></width>
<hfive></hfive>
<headline></headline>
<summary></summary>
</video>

Multiple filters work together. Match multiple filter types together

I have several different filter types.The type of filters is checkbox and rang-price and select-option.Each of these filters works individually.But I want group filters to work.please help my.
let FlyList = [{
"id": "1",
"flight_number": "961",
"type_ticket": "systemi",
"airline": "ata",
"fly_time": "04:00",
"class_type": "economy",
"price": "10000",
"capacity": "2",
}, {
"id": "2",
"flight_number": "960",
"type_ticket": "chartery",
"airline": "Air-Tour",
"fly_time": "08:00",
"class_type": "Business",
"price": "20000",
"capacity": "3",
}, {
"id": "3",
"flight_number": "950",
"type_ticket": "systemi",
"airline": "taban",
"fly_time": "11:00",
"class_type": "Business",
"price": "30000",
"capacity": "5",
},
];
let filters = new Array();
function rangeSlider() {
$(".range-slider").ionRangeSlider({
hide_min_max: true,
keyboard: true,
min: 0,
max: 150,
from: 0,
to: 140,
type: 'double',
step: 1,
prefix: "$",
grid: true,
onFinish: function(data) {
var _price = filters.findIndex(item => item.field === 'price');
if (_price != -1) filters[_price]['value'] = [data.from, data.to];
else addOrRemoveFilter('price', [data.from, data.to], true);
customFilter();
// console.log(addOrRemoveFilter('price', [data.from, data.to], true));
}
});
}
function customFilter() {
let filtered_list = [];
FlyList.filter(item => {
filters.forEach(function(el, i) {
let _field = el['field'];
let _value = el['value'];
// console.log(_value);
if (typeof(_value) === 'object' && _value.length) {
if(parseInt(item[_field]) >= (parseInt(_value[0] * 1000)) && parseInt(item[_field]) <= (parseInt(_value[1]*1000))){
filtered_list.push(item);
}
else{
FlyList = [];
}
} else {
let isMulti = _value.split(',');
//RANGE PRICE SLIDER
if (isMulti.length > 1) {
let time = miliseconds(item[_field].split(':')[0], item[_field].split(':')[1])
let num1 = miliseconds(isMulti[0].split(':')[0], isMulti[0].split(':')[1]);
let num2 = miliseconds(isMulti[1].split(':')[0], isMulti[1].split(':')[1]);
if (time >= num1 && time <= num2) filtered_list.push(item);
} else {
//end RANGE PRICE SLIDER
item[_field] == _value ? filtered_list.push(item) : false;
}
}
})
});
function miliseconds(hrs,min) {
return((hrs*60*60+min*60)*1000);
}
$('#flights').updateDom(filtered_list.length ? filtered_list : FlyList, {
animate: true,
});
}
let filterCheckboxes = document.querySelectorAll('.filtersAll');
filterCheckboxes.forEach(checkbox => checkbox.addEventListener('change', (e) => {
e.preventDefault();
let filterTypeElement = findFilterTypeElement(e.target);
if (filterTypeElement) {
let field = filterTypeElement.getAttribute('data-field');
let val = e.target.value;
addOrRemoveFilter(field,val,e.target.checked);
customFilter();
}
}));
document.getElementById('optionAll').addEventListener('change' ,(e)=>{
e.preventDefault();
let filterTypeElement = findFilterTypeElement(e.target);
if (filterTypeElement) {
let field = filterTypeElement.getAttribute('data-field');
let val = e.target.value;
addOrRemoveFilter(field,val,true);
for(var index = 0 ; index < e.target.options.length ; index++)
{
addOrRemoveFilter(field,e.target.options[index].value,false);
}
addOrRemoveFilter(field,val,true);
customFilter();
}
})
function addOrRemoveFilter(f,v,add) {
if(add) {
filters.push({field : f.toLowerCase() , value : v});
} else {
for(let i = 0;i < filters.length ; i++) {
if(filters[i].field === f.toLowerCase() && filters[i].value === v) {
filters.splice(i,1);
}
}
}
// console.log(filters);
}
function getParents(el, parentSelector /* optional */) {
// If no parentSelector defined will bubble up all the way to *document*
if (parentSelector === undefined) {
parentSelector = document;
}
var parents = [];
var p = el.parentNode;
while (p && (p !== parentSelector || p.parentNode)) {
var o = p;
parents.push(o);
p = o.parentNode;
}
parents.push(parentSelector); // Push that parentSelector you wanted to stop at
return parents;
}
function findFilterTypeElement(el) {
var result = null;
var parents = getParents(el);
parents.forEach((item) => {
if (hasClass(item, 'filter_type') && result == null) {
result = item;
}
});
return result;
}
function hasClass(element, className) {
return (' ' + element.className + ' ').indexOf(' ' + className + ' ') > -1;
}

Collapse nested objects into flat map with dotted properties

I have an object like this
{
"CPU": {
"Architecture": {
"X86": 0,
"Other": 0,
"X86_64": 6
}
},
"Platform": {
"Os": {
"Mac": 0,
"Linux": 5,
"Other": 0,
"Windows": 0
}
}
}
How to to convert it to map like this?
"CPU.Architecture.X86": 0
"Platfrom.Os.Mac":0
"Platfrom.Os.Linux":5
Can there already be ready-made solutions?
If your goal is to concatenate nested object property keys, there is no built-in function for that. However, it is quite simple to implement your own solution:
// Concatenate nested object property keys with a dot:
function dotnotation(obj, dst = {}, prefix = '') {
Object.entries(obj).forEach(([key, val]) => {
if (val && typeof val == 'object') dotnotation(val, dst, prefix + key + '.');
else dst[prefix + key] = val;
});
return dst;
}
// Example:
console.log(dotnotation({a:{b:1, c:2}, d:3})); // {'a.b':1, 'a.c':2, 'd':3}
Object.entries() is part of the upcoming ES2017 standard.
You could try something like this, assuming your object are simply created from data:
function flatten(obj, prev = "", res = {}){
for(f in obj){
if (obj.hasOwnProperty(f)){
if(obj[f].constructor === Object){
prev = prev + f + ".";
flatten(obj[f], prev, res);
}else{
res[prev + f] = obj[f];
}
}
}
return res;
}
let a = {
"CPU": {
"Architecture": {
"X86": 0,
"Other": 0,
"X86_64": 6
}
},
"Platform": {
"Os": {
"Mac": 0,
"Linux": 5,
"Other": 0,
"Windows": 0
}
}
};
console.log(flatten(a))
It will use the for... in loop.
// more consisely
function flatten(obj, prev = "", res = {}){
for(f in obj){
if (obj.hasOwnProperty(f)){
if (obj[f].constructor === Object){
if(typeof obj[f] !== "object") res[prev + f] = obj[f];
else flatten(obj[f], prev + f + ".", res);
}
}
}
return res;
}

How to change key number?

I have this object:
a = {"formData": {
"total": "60.00",
"tr0_RTN": "PZH",
"tr0_amount": "10.00",
"tr2_RTN": "SUB",
"tr2_amount": "30.00",
"tr7_RTN": "KFC",
"tr7_amount": "20.00",
}};
How can I change the key sequence to this:
a = {"formData": {
"total": "60.00",
"tr0_RTN": "PZH",
"tr0_amount": "10.00",
"tr1_RTN": "SUB",
"tr1_amount": "30.00",
"tr2_RTN": "KFC",
"tr2_amount": "20.00",
}};
Anyway I could do this with native or lodash?
You could get all relevant keys, look for the parts and build new consecutive numbers.
Then assign the old values to the new properties and delete the old keys.
old key new key action
---------- ---------- --------------------------------------------
tr0_RTN tr0_RTN no, because old key and new key are the same
tr0_amount tr0_amount same as above
tr2_RTN tr1_RTN create new key, delete old key
tr2_amount tr1_amount same
tr7_RTN tr2_RTN same
tr7_amount tr2_amount same
var a = { "formData": { "total": "60.00", "tr0_RTN": "PZH", "tr0_amount": "10.00", "tr2_RTN": "SUB", "tr2_amount": "30.00", "tr7_RTN": "KFC", "tr7_amount": "20.00", } };
Object.keys(a.formData).filter(function (k) {
return k.indexOf('tr') === 0;
}).sort(function (a, b) {
return a.match(/\d+/) - b.match(/\d+/);
}).forEach(function (k) {
var m = k.match(/(\d+)_(.*)/),
kk;
if (m[1] !== this.last) {
this.counter++;
this.last = m[1];
}
kk = 'tr' + this.counter + '_' + m[2];
if (k !== kk) {
a.formData[kk] = a.formData[k];
delete a.formData[k];
}
}, { counter: -1, last: '' });
console.log(a);
You may do as follows;
var data = {"formData": { "total": "60.00",
"tr0_RTN": "PZH",
"tr0_amount": "10.00",
"tr2_RTN": "SUB",
"tr2_amount": "30.00",
"tr7_RTN": "KFC",
"tr7_amount": "20.00",
}
},
propsToDel = ["tr2_RTN", "tr2_amount", "tr7_RTN", "tr7_amount"],
propsToIns = ["tr1_RTN", "tr1_amount", "tr2_RTN", "tr2_amount"],
newData = propsToIns.reduce((o,p,i) => { o.formData[p] = o.formData[propsToDel[i]];
delete o.formData[propsToDel[i]];
return o;
},data);
console.log(newData);
I imagine you're having a form with tr rows, and you'd like to rearrange them. As the indeces are pretty much random, you can use this function to organize/reindex them.
var keys = Object.keys(a["formData"]);
var formData = {};
var index = 0;
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
if (key.indexOf('tr') == 0) {
if (key.indexOf('_RTN') >= 0) {
key = 'tr' + index + '_RTN';
} else if (key.indexOf('_amount') >= 0) {
key = 'tr' + index + '_amount';
}
if ((formData.hasOwnProperty('tr' + index + '_RTN')
|| formData.hasOwnProperty('tr' + index + '_amount'))
&& !formData.hasOwnProperty(key)) {
index++;
}
}
formData[key] = a["formData"][keys[i]];
}
a["formData"] = formData;
This will rebuild your object with altered keys for the respective _RTN and _amount items.

Remove duplicate values from json array using angular js

I want to remove duplicates from the following json array
$scope.array = [
{"name":"aaa","key":"1"},
{"name":"bbb","key":"2"},
{"name":"aaa","key":"1"},
{"name":"ccc","key":"3"},
{"name":"bbb","key":"2"}
];
I tried following code but its not working
var ids = {};
$scope.array.forEach(function (list) {
ids[list.name] = (ids[list.name] || 0) + 1;
});
var finalResult = [];
$scope.array.forEach(function (list) {
if (ids[list.name] === 1) finalResult.push(student);
});
console.log(finalResult);
This is the expected result.
$scope.array = [
{"name":"aaa","key":"1"},
{"name":"bbb","key":"2"} ,
{"name":"ccc","key":"3"}
];
You can do something like this using Array#filter
$scope = {};
$scope.array = [{
"name": "aaa",
"key": "1"
}, {
"name": "bbb",
"key": "2"
}, {
"name": "aaa",
"key": "1"
}, {
"name": "ccc",
"key": "3"
}, {
"name": "bbb",
"key": "2"
}];
var ids = {};
$scope.array = $scope.array.filter(function(v) {
var ind = v.name + '_' + v.key;
if (!ids[ind]) {
ids[ind] = true;
return true;
}
return false;
});
console.log($scope.array);
You can use the unique filter.
<tr ng-repeat="arr in array | unique: 'key'" >
<td> {{ arr.name }} , {{ arr.key }} </td>
</tr>
You can use
$scope.array = = [{
"testada": "ecom",
"id": "27"
}, {
"testada": "alorta",
"id": "27"
}, {
"testada": "france24",
"id": "23"
}, {
"testada": "seloger",
"id": "23"
}];
var arr = [],
collection = [];
$scope.array.forEach(json_all, function (index, value) {
if ($.inArray(value.id, arr) == -1) {
arr.push(value.id);
collection.push(value);
}
});
console.log(json_all);
console.log(collection);
console.log(arr);
$scope.array = [
{"name":"aaa","key":"1"},
{"name":"bbb","key":"2"},
{"name":"aaa","key":"1"},
{"name":"ccc","key":"3"},
{"name":"bbb","key":"2"}
];
var newArr = []; //this will be new array with no duplicate value
for (var i = 0; i < $scope.array.length; i++) {
if(!ifContains($scope.array[i])){
newArr.push($scope.array[i]);
}
}
function ifContains(obj){
debugger
var flag = false;
for(var i = 0; i < newArr.length; i++){
if(newArr[i].name == obj.name && newArr[i].key == obj.key )
return true;
else
flag = false;
}
return flag;
}
It can be very simply done by pure JS. An invention of Object.prototype.compare() will help us enormously. Let's see how it works;
Object.prototype.compare = function(o){
var ok = Object.keys(this);
return typeof o === "object" && ok.length === Object.keys(o).length ? ok.every(k => this[k] === o[k]) : false;
};
var myArray = [
{"name":"aaa","key":"1"},
{"name":"bbb","key":"2"},
{"name":"aaa","key":"1"},
{"name":"ccc","key":"3"},
{"name":"bbb","key":"2"}
],
filtered = myArray.reduce((p,c) => p.findIndex(f => c.compare(f)) == -1 ? p.concat(c) : p,[]);
console.log(JSON.stringify(filtered));
Note: Object.prototype.compare() v.01 won't do deep object comparison as of now.
var uniqueList = _.uniq($scope.array, function (item) {
return item.key;
});
console.log(uniqueList);
use underscore.js, anyone helps out so post later.
you can use pure javascript!
uniqueArray = a.filter(function(item, pos) {
return a.indexOf(item) == pos;
})
in your case:
var finalResult = [];
finalResult = $scope.array.filter(function(item, pos) {
return array.indexOf(item) == pos;
})

Categories

Resources