Configurable Product
Hi,
I'm trying to generate configurable products for the selected attributes using JavaScript.
I want to generate 3.0_Aluminium_1219, 3.0_Amber_1219, 3.8_Aluminium_1219 and 3.8_Amber_1219.
I have used the following script to store the option value in array
$('.complexSel').on('select2:select', function (e) {
var obj = {}
var keysArray = new Array();
var price = $('.complexSel').find(':selected');
$.each(price, function(index){
keysArray.push($(this).attr('data-mst-id'));
if($(this).attr('data-mst-id') in obj ) {
obj[$(this).attr('data-mst-id')].push({id:$(this).val(),text:$(this).text()});
}else{
obj[$(this).attr('data-mst-id')] = new Array();
obj[$(this).attr('data-mst-id')].push({id:$(this).val(),text:$(this).text()});
}
});
var unique = keysArray.filter(function(itm, i, keysArray) {
return i == keysArray.indexOf(itm);
});
console.log(obj);
});
Please help me to achieve the result
used the following function to solve this issue.
$('.complexSel').on('change', function (e) {
var obj = {}
//var obj = new Array();
var price = $('.complexSel').find(':selected');
$.each(price, function(index){
if($(this).attr('data-mst-val') in obj ) {
obj[$(this).attr('data-mst-val')].push($(this).text());
}else{
obj[$(this).attr('data-mst-val')] = new Array();
obj[$(this).attr('data-mst-val')].push($(this).text());
}
});
var cartesianRes = getCartesian(obj);
console.log(cartesianRes);
/* OUTPUT AS FOLLOWS*/
/*
[
{
"Size": "3.0",
"Color": "Aluminum"
},
{
"Size": "3.0",
"Color": "Amber"
},
{
"Size": "3.8",
"Color": "Aluminum"
},
{
"Size": "3.8",
"Color": "Amber"
}
]
*/
});
function getCartesian(object) {
return Object.entries(object).reduce((r, [k, v]) => {
var temp = [];
r.forEach(s =>
(Array.isArray(v) ? v : [v]).forEach(w =>
(w && typeof w === 'object' ? getCartesian(w) : [w]).forEach(x =>
temp.push(Object.assign({}, s, { [k]: x }))
)
)
);
return temp;
}, [{}]);
}
Related
Given the following object:
const ourObject = {
"payload": {
"streams": [
{
"children": {
"2165d20a-6276-468f-a02f-1abd65cad618": {
"additionalInformation": {
"narrative": {
"apple": "A",
"banana": "B"
},
"myInventory": {
"fruits": [
{
"name": "apple"
},
{
"name": "banana"
}
]
}
}
}
}
}
]
}
};
We're trying to find the path of myInventory, the issue is that the children's uuid will be different each time. Any idea how we can get the path to myInventory by providing it as a key and get the json path to it?
If things are dynamic, a programmatic key search could help
const ourObject = {
"payload": {
"streams": [
{
"children": {
"2165d20a-6276-468f-a02f-1abd65cad618": {
"additionalInformation": {
"narrative": {
"apple": "A",
"banana": "B"
},
"myInventory": {
"fruits": [
{
"name": "apple"
},
{
"name": "banana"
}
]
}
}
}
}
}
]
}
};
const getPath = (key, o) => {
if (!o || typeof o !== "object") {
return "";
}
const keys = Object.keys(o);
for(let i = 0; i < keys.length; i++) {
if (keys[i] === key ) {
return key;
}
const path = getPath(key, o[keys[i]]);
if (path) {
return keys[i] + "." + path;
}
}
return "";
};
const getValueForKey = (key, o) => {
if (!o || typeof o !== "object") {
return undefined;
}
const keys = Object.keys(o);
for(let i = 0; i < keys.length; i++) {
if (keys[i] === key ) {
return o[key];
}
const value = getValueForKey(key, o[keys[i]]);
if (value) {
return value;
}
}
return undefined;
}
console.log(getPath("myInventory", ourObject))
console.log(getValueForKey("myInventory", ourObject))
Not sure if I understand the question right but
let uuid = '2165d20a-6276-468f-a02f-1abd65cad618';
ourObject.payload.streams[0].children[uuid].additionalInformation.myInventory
var changingKey = Object.keys(ourObject["payload"]["streams"][0]["children"])[0];
console.log(ourObject["payload"]["streams"][0]["children"][changingKey]["additionalInformation"]["myInventory"]);
Okay, you could create a helper function that gets the UUID. Since it's an object, the lookup is close to O(1) especially given the case that the children has only one key-value pair here.
function getUUIDFromPayload(payload) {
let obj = payload.streams[0].children
let uuid = Object.keys(obj)[0]
return uuid
}
Usage
const uuid = getUUIDFromPayload(payload)
ourObject.payload.streams[0].children[uuid].additionalInformation.myInventory
My existing array object are
//existing object
var existing = [
{
'ProviderCode':'aa',
'msg':'....',
},{
'ProviderCode':'bb',
'msg':'....',
},{
'ProviderCode':'cc',
'msg':'....',
},{
'ProviderCode':'dd',
'msg':'....',
},{
'ProviderCode':'ee',
'msg':'....',
}];
new object I'm comparing to
var new = [
{
'ProviderCode':'bb',
'msg':'....',
},{
'ProviderCode':'cc',
'msg':'....',
},{
'ProviderCode':'ee',
'msg':'....',
},{
'ProviderCode':'ff',
'msg':'....',
},{
'ProviderCode':'gg',
'msg':'....',
}];
I would like to generate same, remove and add array based on the two array objects, I can get the same array object but not the remove and add object from the objects.
var same = []; //bb, cc, ee //these will be the match
var remove = []; //aa , dd //will be remove from existing
var add = []; //ff, gg //will be consider as add
//I can get the same using below:
e.forEach(function(ev,ei,ea){
n.forEach(function(nv,ni,na){
if( ev.ProviderCode === nv.ProviderCode ){
s.push({ProviderCode:ev.ProviderCode,msg:"Same, do nothing"});
}
});
});
/* //output:
[{
"ProviderCode": "bb",
"msg": "Same, do nothing"
}, {
"ProviderCode": "cc",
"msg": "Same, do nothing"
}, {
"ProviderCode": "ee",
"msg": "Same, do nothing"
}]
*/
//but how do I get remove and add array object?
//remove will be:
/* //output:
[{
"ProviderCode": "aa",
"msg": "removed"
}, {
"ProviderCode": "dd",
"msg": "removed"
}]
*/
//add will be:
/* //output:
[{
"ProviderCode": "ff",
"msg": "added"
}, {
"ProviderCode": "gg",
"msg": "added"
}]
*/
You can use Array.prototype.filter & Array.prototype.find for this:
let existing = [{ProviderCode:'aa'},{ProviderCode:'bb'},{ProviderCode:'cc'},{ProviderCode:'dd'},{ProviderCode:'ee'}];
let newData = [{ProviderCode:'bb'},{ProviderCode:'cc'},{ProviderCode:'ee'},{ProviderCode:'ff'},{ProviderCode:'gg'}];
let added = newData.filter(d => !existing.find(e => d.ProviderCode === e.ProviderCode));
console.log("ADDED:", added);
let removed = existing.filter(d => !newData.find(e => d.ProviderCode === e.ProviderCode));
console.log("REMOVED:", added);
let same = newData.filter(d => existing.find(e => d.ProviderCode === e.ProviderCode));
console.log("SAME:", same);
With a library like lodash this is a bit easier:
let existing = [{ProviderCode:'aa'},{ProviderCode:'bb'},{ProviderCode:'cc'},{ProviderCode:'dd'},{ProviderCode:'ee'}];
let newData = [{ProviderCode:'bb'},{ProviderCode:'cc'},{ProviderCode:'ee'},{ProviderCode:'ff'},{ProviderCode:'gg'}];
console.log("ADDED:" , _.differenceBy(newData, existing, 'ProviderCode'));
console.log("REMOVED:", _.differenceBy(existing, newData, 'ProviderCode'));
console.log("SAME:" , _.intersectionBy(newData, existing, 'ProviderCode'));
<script src="https://unpkg.com/lodash#4.17.15/lodash.min.js"></script>
You can use this little "library" that provides set operations for JS Map objects:
function mapUnion(m1, m2) {
let m = new Map();
for (let [k, v] of m1)
m.set(k, v);
for (let [k, v] of m2)
m.set(k, v);
return m;
}
function mapIntersection(m1, m2) {
let m = new Map();
for (let [k, v] of m1)
if (m2.has(k))
m.set(k, v);
return m;
}
function mapDifference(m1, m2) {
let m = new Map();
for (let [k, v] of m1)
if (!m2.has(k))
m.set(k, v);
return m;
}
Having this, you can convert both your arrays to Maps:
let m1 = new Map(oldArray.map(x => [x.ProviderCode, x]))
let m2 = new Map(newArray.map(x => [x.ProviderCode, x]))
and do whatever you want with these, for example,
console.log(mapIntersection(m1, m2)) // bb=>..., cc=>..., ee=>...
console.log(mapDifference(m1, m2)) // aa=>..., dd=>...
If you need arrays as results:
commonObjects = Array.from(mapIntersection(m1, m2).values())
You could take some sets and get the wanted items for each change.
const
providerCode = ({ ProviderCode }) => ProviderCode;
var existingData = [{ ProviderCode: 'aa' }, { ProviderCode: 'bb' }, { ProviderCode: 'cc' }, { ProviderCode:'dd' }, { ProviderCode: 'ee' }],
newData = [{ ProviderCode: 'bb' }, { ProviderCode: 'cc' }, { ProviderCode: 'ee' }, { ProviderCode: 'ff' }, { ProviderCode: 'gg' }],
existingSet = new Set(existingData.map(providerCode)),
newSet = new Set(newData.map(providerCode)),
same = [...existingSet].filter(Set.prototype.has, newSet),
add = [...newSet].filter(v => !existingSet.has(v)),
remove = [...existingSet].filter(v => !newSet.has(v));
console.log(...same);
console.log(...add);
console.log(...remove);
Before
This is an object with multiple rows:
{
"functions": [
{
"package_id": "2",
"module_id": "2",
"data_id": "2"
},
{
"package_id": "1",
"module_id": "1",
"data_id": "2"
},
{
"package_id": "2",
"module_id": "3",
"data_id": "3"
}
]
}
Desired result
I want this to return into a "nested" Object like below, without duplicates:
{
"packages": [
{
"package_id": "2",
"modules": [
{
"module_id": "2",
"data": [
{
"data_id": "2"
}
]
},
{
"module_id": "3",
"data": [
{
"data_id": "3"
}
]
}
]
},{
"package_id": "1",
"modules": [
{
"module_id": "1",
"data": [
{
"data_id": "2"
}
]
}
]
}
]
}
I've already tried loops inside loops, with constructing multiple arrays and objects. Which causes duplicates or overriding objects into single ones. Is there a more generic way to generate this with JavaScript? (It's for an Angular (6) project.
Example 1
getFunctionPackage() {
var fList = this.functionList;
var dArr = [];
var dObj = {};
var pArr = [];
var pObj = {};
var mArr = [];
var mObj = {};
for (var key in fList) {
pObj['package_id'] = fList[key]['package_id'];
mObj['module_id'] = fList[key]['module_id'];
dObj['data_id'] = fList[key]['data_id'];
for (var i = 0; i < pArr.length; i++) {
if (pArr[i].package_id != pObj['package_id']) {
pArr.push(pObj);
}
for (var x = 0; x < mArr.length; x++) {
if (pArr[i]['modules'][x].module_id != mObj['module_id']) {
mArr.push(mObj);
}
for (var y = 0; y < dArr.length; y++) {
if (pArr[i]['modules'][x]['datas'][y].data_id != dObj['data_id']) {
dArr.push(dObj);
}
}
}
}
if (dArr.length == 0) {
dArr.push(dObj);
}
mObj['datas'] = dArr;
if (mArr.length == 0) {
mArr.push(mObj);
}
pObj['modules'] = mArr;
if (pArr.length == 0) {
pArr.push(pObj);
}
dObj = {};
mObj = {};
pObj = {};
}
}
Example 2:
Results in skipping cause of the booleans
var fList = this.functionList;
var dArr = [];
var dObj = {};
var pArr = [];
var pObj = {};
var mArr = [];
var mObj = {};
var rObj = {};
for (var key in fList) {
pObj['package_id'] = fList[key]['package_id'];
mObj['module_id'] = fList[key]['module_id'];
dObj['data_id'] = fList[key]['data_id'];
var pfound = false;
var mfound = false;
var dfound = false;
for (var i = 0; i < pArr.length; i++) {
if (pArr[i].package_id == pObj['package_id']) {
for (var x = 0; x < mArr.length; x++) {
if (pArr[i]['modules'][x].module_id == mObj['module_id']) {
for (var y = 0; y < dArr.length; y++) {
if (pArr[i]['modules'][x]['datas'][y].data_id == dObj['data_id']) {
dfound = true;
break;
}
}
mfound = true;
break;
}
}
pfound = true;
break;
}
}
if (!dfound) {
dArr.push(dObj);
mObj['datas'] = dArr;
dObj = {};
}
if (!mfound) {
mArr.push(mObj);
pObj['modules'] = mArr;
mObj = {};
}
if (!pfound) {
pArr.push(pObj);
pObj = {};
}
dArr = [];
mArr = [];
}
rObj['packages'] = pArr;
console.log(rObj);
Here's a more generic approach using Array#reduce() to create a grouped object based on the package id as keys. You can use any loop to build this same object ...for() or forEach() for example.
Then use Object.values() to get the final array from that grouped object
Using methods like Array#find() simplifies traversing to see if a module exists already or not within each package
const grouped = data.functions.reduce((a, c )=>{
// if group object doesn't exist - create it or use existing one
a[c.package_id] = a[c.package_id] || {package_id : c.package_id, modules: [] }
// store reference to the group modules array
const mods = a[c.package_id].modules
// look within that group modules array to see if module object exists
let module = mods.find(mod => mod.module_id === c.module_id)
if(!module){
// or create new module object
module = {module_id: c.module_id, data:[]}
// and push it into modules array
mods.push(module);
}
// push new data object to module data array
module.data.push({data_id: c.data_id})
return a
}, {})
// create final results object
const res = { packages : Object.values(grouped) }
console.log(res)
.as-console-wrapper {max-height: 100%!important;}
<script>
const data = {
"functions": [{
"package_id": "2",
"module_id": "2",
"data_id": "2"
},
{
"package_id": "1",
"module_id": "1",
"data_id": "2"
},
{
"package_id": "2",
"module_id": "3",
"data_id": "3"
}
]
}
</script>
I have an array which i need to compare it's values - and if there are duplication - i want to store them in array, for example :
obj1 = [{"manager_id":1,"name":"john"},{"manager_id":1,"name":"kile"},
{"manager_id":2,"name":"kenny"},
{"manager_id":4,"name":"stan"}]
obj2 = [{"employees_id":1,"name":"dan"},
{"employees_id":1,"name":"ben"},{"employees_id":1,"name":"sarah"},
{"employees_id":2,"name":"kelly"}]
If "manger_id" === "employees_id - then the result would be :
// {1:[{"manager_id":1,"name":"john"},{"manager_id":1,"name":"kile"},
{"employees_id":1,"name":"dan"}, {"employees_id":1,"name":"ben"},
{"employees_id":1,"name":"sarah"}]};
I've tried :
var obj1 = [{
"manager_id": 1,
"name": "john"
}, {
"manager_id": 1,
"name": "kile"
}, {
"manager_id": 2,
"name": "kenny"
}, {
"manager_id": 4,
"name": "stan"
}];
var obj2 = [{
"employees_id": 1,
"name": "dan"
}, {
"employees_id": 1,
"name": "ben"
}, {
"employees_id": 1,
"name": "sarah"
}, {
"employees_id": 2,
"name": "kelly"
}];
var res = obj1.concat(obj2).reduce(function(r, o) {
r[o.manager_id] = r[o.employees_id] || [];
r[o.manager_id].push(o);
return r;
}, {});
console.log(res);
.as-console-wrapper {
max-height: 100% !important;
top: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div></div>
As you can the results of the "manager_id" aren't added - only one - when there should be more
if manager_id === employees_id // should output in the first key
{1:[{"manager_id":1,"name":"john"},{"manager_id":1,"name":"kile"},
{"employees_id":1,"name":"dan"}, {"employees_id":1,"name":"ben"},
{"employees_id":1,"name":"sarah"}]};
As you can see there are several common id's
r[o.manager_id] = r[o.employees_id] || []; in this statement if a manager didn't have an employee_id the array was being reset for that id.
One way doing it right is this:
var res = obj1.concat(obj2).reduce(function(r, o) {
var id;
if(o.hasOwnProperty('manager_id')) {
id = o['manager_id'];
}
else {
id = o['employees_id'];
}
r[id] = r[id] || [];
r[id].push(o);
return r;
}, {});
The problem relies on this line:
r[o.manager_id] = r[o.employees_id] || [];
You should have in mind that some objects in your arrays have the manager_id and some other don't, they have the employees_id instead, so you have to evaluate that first with this line:
var itemId = o.manager_id || o.employees_id;
Try this code:
var res = obj1.concat(obj2).reduce(function(r, o) {
var itemId = o.manager_id || o.employees_id;
r[itemId] = r[itemId] || [];
r[itemId].push(o);
return r;
}, {});
I have an object like this:
{
"root.apple.color": "red",
"root.apple.shape": "circle",
"root.peach[0].color": "green",
"root.peach[1].color": "yellow",
}
How can I convert it to be an object like this:
{
"root": {
"apple": {
"color": "red",
"shape": "circle"
},
"peach": [
{
"color": "green"
},
{
"color": "yellow"
}
]
}
}
Basically I need a function which will convert any array with values defined as top example to multi-level object with real parameters.
The extended solution using Object.keys, String.split, Array.isArray, Array.forEach functions:
var obj = {
"root.apple.color": "red",
"root.apple.shape": "circle",
"root.peach[0].color": "green",
"root.peach[0].shape": "square",
"root.peach[1].color": "yellow",
"root.apple.info.items[0].type": "text",
"root.apple.info.items[0].active": true,
"root.apple.info.items[1].type": "image",
"root.apple.info.items[1].active": false,
"root.apple.exterior.toggle[0].id": "left",
"root.apple.exterior.toggle[0].content": "Ext",
"root.test": "testing"
},
result = {};
function transformObject(obj, result) {
var current,
checkProp = function (prop, objItem, is_array, idx, val) {
if (Array.isArray(current) && val) {
if (typeof idx === 'number' && current[idx]){
current[idx][prop] = val;
} else {
var o = {};
o[prop] = val;
current.push(o);
}
} else {
objItem[prop] = objItem[prop] || ((!is_array) ? {} : []);
if (val) objItem[prop] = val;
current = objItem[prop];
}
},
re = /\[(\d)\]$/;
Object.keys(obj).forEach(function (k) {
var props = k.split("."),
lastKey = props.length - 1,
val = obj[k], idx;
props.forEach(function (prop, k) {
var is_array = re.test(prop);
if (is_array) { idx = +prop.match(re)[1]; prop = prop.replace(re, ""); };
checkProp(prop, (!current) ? result : current, is_array, idx, (k === lastKey) ? val : null);
});
current = null;
});
return result;
}
console.log(JSON.stringify(transformObject(obj, result), 0, 4));
This implementation works just on object nesting. you can add array awareness to it by yourself.
function nested(obj, strPropertyChain, value) {
var props = strPropertyChain.split('.');
var len = props.length;
var o = obj[props[0]] = (obj[props[0]] || {});
props.slice(1, len - 1)
.forEach(prop => o = (o[prop] = {}));
o[props[len - 1]] = value;
return obj;
}
var obj1 = {
"root.apple.color": "red",
"root.apple.shape": "circle",
"root.peach.color": "green",
"root.pear.color": "yellow",
}
var obj2 = {}
Object.keys(obj1).forEach(k => nested(obj2, k, obj1[k]));
console.log(obj2);
You may do like this;
Object.prototype.setNestedValue = function(...a) {
a.length > 2 ? typeof this[a[0]] === "object" && this[a[0]] !== null ? this[a[0]].setNestedValue(...a.slice(1))
: (this[a[0]] = isNaN(a[1]) ? {} : new Array(a[1]),
this[a[0]].setNestedValue(...a.slice(1)))
: this[a[0]] = a[1];
return this;
};
var data = {
"root.apple.color": "red",
"root.apple.shape": "circle",
"root.peach[0].color": "green",
"root.peach[1].color": "yellow",
},
ok = Object.keys(data),
o = ok.reduce((o,k) => o.setNestedValue(...k.replace("[",".").replace("]","").split(".").concat(data[k])),{});
console.log(JSON.stringify(o));
Object.prototype.setNestedValue() takes a series of arguments of which the last one is the value and the previous ones are, if string type the nested object properties or if integer, array indices. I had to turn your object keys into an array like "root.peach[0].color": "green" -> ["root, "peach", "0", "color", "green"]. Then Object.prototype.setNestedValue() will tell the "0" is in fact an array index.