So, i have this CustomerProfile Class as:
import _customer from '../swaggerCodegen/Customer'
import Address from '../Address'
export default class CustomerProfile {
constructor(customerProfileResponse) {
_customer.constructFromObject(customerProfileResponse,this)
}
}
where constructFromObject is a static function created by Swagger as:
static constructFromObject(data, obj) {
if (data) {
obj = obj || new Customer();
if (data.hasOwnProperty('accountManager')) {
obj['accountManager'] = Employee.constructFromObject(data['accountManager']);
}
if (data.hasOwnProperty('addresses')) {
obj['addresses'] = ApiClient.convertToType(data['addresses'], [Address]);
}
if (data.hasOwnProperty('billingAccounts')) {
obj['billingAccounts'] = ApiClient.convertToType(data['billingAccounts'], [BillingAccount]);
}
if (data.hasOwnProperty('billingStatus')) {
obj['billingStatus'] = ApiClient.convertToType(data['billingStatus'], 'String');
}
if (data.hasOwnProperty('busNumber')) {
obj['busNumber'] = ApiClient.convertToType(data['busNumber'], 'String');
}
if (data.hasOwnProperty('companyName')) {
obj['companyName'] = ApiClient.convertToType(data['companyName'], 'String');
}
if (data.hasOwnProperty('contacts')) {
obj['contacts'] = ApiClient.convertToType(data['contacts'], [Contact]);
}
if (data.hasOwnProperty('customerCode')) {
obj['customerCode'] = ApiClient.convertToType(data['customerCode'], 'String');
}
if (data.hasOwnProperty('email')) {
obj['email'] = ApiClient.convertToType(data['email'], 'String');
}
if (data.hasOwnProperty('gsm')) {
obj['gsm'] = ApiClient.convertToType(data['gsm'], 'String');
}
if (data.hasOwnProperty('idNumber')) {
obj['idNumber'] = ApiClient.convertToType(data['idNumber'], 'String');
}
if (data.hasOwnProperty('segment')) {
obj['segment'] = ApiClient.convertToType(data['segment'], 'String');
}
if (data.hasOwnProperty('subsegment')) {
obj['subsegment'] = ApiClient.convertToType(data['subsegment'], 'String');
}
}
return obj;
}
Also, here the snippet that handle arrays in the covertToType function:
default:
if (type === Object) {
// generic object, return directly
return data;
} else if (typeof type === 'function') {
// for model type like: User
return type.constructFromObject(data);
} else if (Array.isArray(type)) {
// for array type like: ['String']
var itemType = type[0];
return data.map((item) => {
return ApiClient.convertToType(item, itemType);
});
} else if (typeof type === 'object') {
// for plain object type like: {'String': 'Integer'}
var keyType, valueType;
for (var k in type) {
if (type.hasOwnProperty(k)) {
keyType = k;
valueType = type[k];
break;
}
}
var result = {};
for (var k in data) {
if (data.hasOwnProperty(k)) {
var key = ApiClient.convertToType(k, keyType);
var value = ApiClient.convertToType(data[k], valueType);
result[key] = value;
}
}
return result;
Logging obj['addresses'][0] instanceof Address returns true when called from the static method, while logging this.addresses[0] instanceof Address from the CustomerProfile constructor brings me false.
Any insights? Thanks
P.S Calling constructor.name calls returns 'Address'
Related
I would like to use a BehaviorSubject to store an Array of objects and have a way to easily update (next?) a single item of that array without having to update the whole array.
I would also like for an easy way to subscribe to changes to an specific item of that array. I know it could be done with filter, but an easier way would be nice...
Is that possible?
I am currently using this version I created (which I don't know if it is the best way or not) that also persists its contents to localstorage:
export class LocalStorageBehaviorSubject<T, Y = T> {
private _data: BehaviorSubject<T>;
public asObservable() {
return this._data.asObservable();
}
public next(data: T) {
if(this.expirationFn !== null) {
data = this.expirationFn(data);
}
localStorage.setItem(this.key, JSON.stringify(data));
this._data.next(data);
}
public nextItem(item: Y) {
if (!Array.isArray(this._data.getValue())) {
throw "Type is not an Array";
}
let dados: any = (<any>this._data.getValue()).slice();
if (dados.some(r => r[this.id] === item[this.id])) {
dados = dados.map(r => r[this.id] === item[this.id] ? item : r);
} else {
dados.push(item);
}
if(this.expirationFn !== null) {
dados = this.expirationFn(dados);
}
localStorage.setItem(this.key, JSON.stringify(dados));
this._data.next(<any>dados);
}
public removeItem(id) {
if (!Array.isArray(this._data.getValue())) {
throw "Type is not an Array";
}
let dados: any = (<any>this._data.getValue()).slice();
dados = dados.filter(r => r[this.id] !== id);
localStorage.setItem(this.key, JSON.stringify(dados));
this._data.next(<any>dados);
}
public removeExpiredData(){
let data = this.loadFromStorage();
if (data) {
if(this.expirationFn !== null) {
data = this.expirationFn(data);
}
this._data.next(data);
}
}
public getValue() {
this.removeExpiredData();
return this._data.getValue();
}
public getItem(id): Y {
if (!Array.isArray(this._data.getValue())) {
throw "Type is not an Array";
}
this.removeExpiredData();
return (<any>this._data.getValue()).slice().find(t => t[this.id] == id);
}
constructor(private key: string, private id: string, defaultValue: any = null, private expirationFn: (dados: T) => T = null) {
this._data = new BehaviorSubject<T>(defaultValue);
this.removeExpiredData();
}
private loadFromStorage(): T {
let dadosStr = localStorage.getItem(this.key);
if (dadosStr) {
return JSON.parse(dadosStr);
}
return null;
}
}
I hoped that would be an simpler way...
Thanks
I would also like for an easy way to subscribe to changes to an
specific item of that array. I know it could be done with filter, but
an easier way would be nice...
You can use map operator and inside lambda array.find
Example
const mockStorage = {
values: {},
setItem(key, value) {
this.values[key] = value;
},
getItem(key) {
return this.values[key]
},
clearItem(key) {
this.values[key] = undefined;
}
}
class LocalStorageBehaviorSubject {
constructor(key, defaultValue) {
this.key = key;
this._data = new rxjs.BehaviorSubject(defaultValue);
}
nextItem(item) {
const list = this._data.value;
const itemIndex = list.findIndex(pr => pr.id === item.id);
this._data.next([
...list.slice(0, itemIndex),
{
...(list[itemIndex] || {}),
...item
},
...list.slice(itemIndex + 1)
]);
}
removeItem(id) {
this._data.next(this._data.value.filter(pr => pr.id !== id));
}
getItem(id) {
return this.asObservable()
.pipe(
rxjs.operators.map(values => values.find(pr => pr.id === id) || null),
rxjs.operators.distinctUntilChanged());
}
asObservable() {
return this._data.asObservable().pipe(
rxjs.operators.tap(values => {
if (values && values.length) {
mockStorage.setItem(this.key, JSON.stringify(values));
}
else {
mockStorage.clearItem(this.key);
}
}))
}
}
const localStorageBehaviorSubject = new LocalStorageBehaviorSubject('items', []);
localStorageBehaviorSubject
.getItem(1)
.subscribe(item => {
console.log(item);
})
localStorageBehaviorSubject.nextItem({id: 1, value: 'test'})
localStorageBehaviorSubject.nextItem({id: 1, value: 'test1'})
localStorageBehaviorSubject.nextItem({id: 2, value: 'test2'})
localStorageBehaviorSubject.nextItem({id: 3, value: 'test3'})
localStorageBehaviorSubject.removeItem(2);
localStorageBehaviorSubject.removeItem(1);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.5/rxjs.umd.js"></script>
This code works for converting the JSON to an object where each name object turns into the key for either its value, or if it instead has its own element object breaks that out and does the same to its contents.
Is there a better way to do this that would also allow for more extensiblity of the JSON schema?
Is there a way I can get it all down to a simpler function that I can pass the first element and have it convert it down to whatever depth the schema goes?
const fs = require('fs');
{
let scheme = JSON.parse('{"$schema":{"root":{"name":"THINGY","dtd":{"name":"DOCTYPE","value":"something.dtd","commentBefore":["?xml version='1.0'?","Version NULL"]},"ele":{"name":"REPORT","ele":[{"name":"SEGMENT0","ele":[{"name":"NUMBER1","value":""},{"name":"NUMBER2","value":""}]},{"name":"SEGMENT1","ele":[{"name":"RECORD1","ele":[{"name":"NUMBER1","value":""},{"name":"NUMBER2","value":""}]}]},{"name":"SEGMENT2","ele":[]},{"name":"SEGMENT3","ele":[]},{"name":"SEGMENT4","ele":[]},{"name":"SEGMENT5","ele":[]}]}}}}').$schema.root;
let depth = 0;
var compiled = {
[scheme.ele.name]: scheme.ele.ele.map(function(i) {
if (typeof i.ele != 'undefined') {
return {
[i.name]: i.ele.map(function(k) {
if (typeof k.ele != 'undefined') {
return {
[k.name]: k.ele.map(function(p) {
if (typeof p.ele != 'undefined') {
return {
[p.name]: p.ele
};
} else {
return {
[p.name]: p.value
};
}
})
};
} else {
return {
[k.name]: k.value
};
}
})
};
} else {
return {
[i.name]: i.value
};
}
})
};
}
console.log(JSON.stringify(compiled, 0, 2));
I should add, this is intended to eventually also apply validation and grab real data when it gets to the string objects.
The output looks like this:
{
"REPORT": [
{
"SEGMENT0": [
{
"NUMBER1": ""
},
{
"NUMBER2": ""
}
]
},
{
"SEGMENT1": [
{
"RECORD1": [
{
"NUMBER1": ""
},
{
"NUMBER2": ""
}
]
}
]
},
{
"SEGMENT2": []
},
{
"SEGMENT3": []
},
{
"SEGMENT4": []
},
{
"SEGMENT5": []
}
]
}
You could destructure the object, get name, ele and value and return a new object with name as key and either an array by mapping the objects of ele or the value.
const
getData = ({ name, ele, value }) => ({
[name]: Array.isArray(ele)
? ele.map(getData)
: value
});
var scheme = JSON.parse('{"$schema":{"root":{"name":"THINGY","dtd":{"name":"DOCTYPE","value":"something.dtd","commentBefore":["?xml version=\'1.0\'?","Version NULL"]},"ele":{"name":"REPORT","ele":[{"name":"SEGMENT0","ele":[{"name":"NUMBER1","value":""},{"name":"NUMBER2","value":""}]},{"name":"SEGMENT1","ele":[{"name":"RECORD1","ele":[{"name":"NUMBER1","value":""},{"name":"NUMBER2","value":""}]}]},{"name":"SEGMENT2","ele":[]},{"name":"SEGMENT3","ele":[]},{"name":"SEGMENT4","ele":[]},{"name":"SEGMENT5","ele":[]}]}}}}').$schema.root,
result = getData(scheme.ele);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina's answer is cleaner but this looks a bit more like your code so I figured I'd post it anyway.
let scheme = JSON.parse('{"$schema":{"root":{"name":"THINGY","dtd":{"name":"DOCTYPE","value":"something.dtd","commentBefore":["?xml version=\'1.0 \'?","Version NULL"]},"ele":{"name":"REPORT","ele":[{"name":"SEGMENT0","ele":[{"name":"NUMBER1","value":""},{"name":"NUMBER2","value":"1"}]},{"name":"SEGMENT1","ele":[{"name":"RECORD1","ele":[{"name":"NUMBER1","value":"2"},{"name":"NUMBER2","value":""}]}]},{"name":"SEGMENT2","ele":[]},{"name":"SEGMENT3","ele":[]},{"name":"SEGMENT4","ele":[]},{"name":"SEGMENT5","ele":[]}]}}}}').$schema.root;
let newScheme = JSON.parse('{"$schema":{"root":{"name":"THINGY","dtd":{"name":"DOCTYPE","value":"something.dtd","commentBefore":["?xml version=\'1.0 \'?","Version NULL"]},"ele":{"name":"REPORT","ele":[{"name":"SEGMENT0","ele":[{"name":"NUMBER1","value":"1"},{"name":"NUMBER2","value":"3"}]},{"name":"SEGMENT1","ele":[{"name":"RECORD1","ele":[{"name":"NUMBER1","value":"4"},{"name":"NUMBER2","value":""}]}]},{"name":"SEGMENT2","ele":[]},{"name":"SEGMENT3","ele":[]},{"name":"SEGMENT4","ele":[]},{"name":"SEGMENT5","ele":[]}]}}}}').$schema.root;
//Yay, recursion!
function mapObj(a, o = {}) {
let array = o[a.name] || [];
for (let i = 0; i < a.ele.length; i++) {
let b = a.ele[i];
array[i] = b.ele ?
mapObj(b, array[i]) : {
[b.name]: b.value
};
}
o[a.name] = array;
return o;
}
let obj = mapObj(scheme.ele);
console.log(obj);
console.log(mapObj(newScheme.ele, obj));
I have a nested object which looks like this :
let obj = {
_id:{}
person:{
$search:{fname:true}
_id:{},
fname:{}
},
code:{},
vnvEmpName:{}
}
I have to search for a $search keyword in this and get the key which is inside it that is fname in this case, it can contain multiple keys as well and I have to retrieve all of it.
I tried something like this :
function findById(obj, id) {
var result;
for (var p in obj) {
if (obj.id === id) {
return obj;
} else {
if (typeof obj[p] === 'object') {
result = findById(obj[p], id);
if (result) {
return result;
}
}
}
}
return result;
}
If the object is in this way :
let obj = {
_id: {},
person: {
$search: {
lname: true
},
_id: {},
fname: {},
something:{
$search: {
fname: true
},
}
},
code: {},
$search: {
mname: true
},
vnvEmpName: {}
}
I want to retrieve all the attributes inside the $search of every block.
but I don't know how to get the keys inside a particular key as I am so new to the javascript.
To just get the keys you can simply do it using Object.keys(yourObject) MDN Object.keys
You can also use lodash to obtain the same result
Need to recursively search through the object
let obj = {
_id: {},
person: {
$search: {
fname: true
},
_id: {},
fname: {}
},
code: {},
vnvEmpName: {}
}
function findById(obj, id) {
var result = "";
// iterate the object using for..in
for (var keys in obj) {
// check if the object has any property by that name
if (obj.hasOwnProperty(keys) && typeof obj[keys] === 'object') {
// if the key is not undefined get it's value
if (obj[keys][id] !== undefined) {
result = (obj[keys][id])
} else {
// else again call the same function using the new obj value
findById(obj[keys], id)
}
}
}
return result;
}
console.log(findById(obj, 'fname'))
You can use the following function:
const objectifier = function (splits, create, context) {
let result = context;
for (let i = 0, key; result && (key = splits[i]); i += 1) {
if (key in result) { result = result[key]; } else {
result = create
? result[key] = {}
: undefined;
}
}
return result;
};
Have a look at the example below:
let obj = {
'_id': {aa: 'aa'},
'person': {
'$search': {
'fname': true
},
'_id': {'bb': 'bb'},
'fname': {'cc': 'cc'}
},
'code': {'dd': 'dd'},
'vnvEmpName': {'name': 'sdsdd'}
}
const objectifier = function (splits, create, context) {
let result = context;
for (let i = 0, key; result && (key = splits[i]); i += 1) {
if (key in result) { result = result[key]; } else {
result = create
? result[key] = {}
: undefined;
}
}
return result;
};
console.log(objectifier('person.$search'.split('.'), false, obj));
// { fname: true }
I have below method where i get value from the nested object , want to refactor it to best possible way but cannot use Object.hasOwnProperty because of linting rules
export const getValueFromNestedObject = (obj = {}, key = '') => {
let result;
for (let i = 0; i< Object.keys(obj).length; i++) {
if (typeof obj[Object.keys(obj)[i]] === 'object') {
result = getValueFromNestedObject(obj[Object.keys(obj)[i]], key);
if(typeof result != 'undefined') {
return result;
}
} else if (Object.keys(obj)[i] === key) {
return obj[key];
}
}
}
const valueObj = {
'#close' : {
'type': 'button',
'dom' : {
'data-linkName' : 'Close'
}
},
'#popupText': {
'type': 'HTML',
'options': {
'html': 'Pop Up Text that is required as result'
'label': 'Heads Up'
}
}
};
const key = 'html';
console.log(getValueFromNestedObject(valueObj, key));
expect(getValueFromNestedObject(valueObj, key)).toEqual('Pop Up Text that is required as result')
I have a big problem and I need your help.
I have a object like this:
{
folder1: {
folderid: 1,
files: {
name: "yeah.txt"
},
folder2: {
folderid: 2
folder3: {
folderid: 3
}
}
},
folder4: {
folderid: 4
}
}
and I want to search for the key "folderid = 3" and find the object.
How can I do this in JavaScript?
Kind regards and thanks for your help
I came to a more generalised solution, that supports multiple properties check:
function search(obj, properties){
if(Object.keys(properties).every(function(key){
return obj[key] === properties[key];
})) {
return obj;
} else {
Object.keys(obj).forEach(function(key){
var child = obj[key];
if(child !== null && typeof child === 'object'){
return search(child, properties);
}
});
return false;
}
}
demo: http://jsfiddle.net/dzs1orbw/
You can use a DSF algorithm to do this: http://jsfiddle.net/L5b07bt6/
var obj = {
folder1: {
folderid: 1,
files: {
name: "yeah.txt"
},
folder2: {
folderid: 2,
folder3: {
folderid: 3,
caption: "I got it!"
}
}
},
folder4: {
folderid: 4
}
};
function find(root, id) {
if (root.folderid == id) return root;
if (typeof root !== 'object') return null;
var key, val;
for (key in root) {
val = find(root[key], id);
if (val != null) return val;
}
return null;
}
var result = find(obj, 3);
if (!result) alert("Not found!");
else alert("Found: " + result.caption);
and here another one:
function findByKey (object, searchKey){
if(typeof object !== 'object'){
return false;
}
for(var key in object){
if(object[key] === searchKey){
return object;
} else {
if(typeof (object[key] === 'object')){
var result = findByKey(object[key], searchKey);
if(result){
return result;
}
}
}
}
}
http://jsfiddle.net/mattposch/ebmd8xtk/