var context = {};
let head;
context.head = new Proxy({}, {
get(obj, prop) {
if (!head) {
head = {
htmlAttrs: {
lang: 'Fr'
}
}
}
if (prop === 'htmlAttrs') {
return `${JSON.stringify(head.htmlAttrs)}`
}
},
set(obj, prop, value, rec) {
return Reflect.set(...arguments);
}
})
context.head.htmlAttrs = {
key: true
}
console.log(context.head.htmlAttrs)
Now it log just lang: 'Fr' how to get it to log key: truetoo
In this case, the obj variable returned by get() contains them:
var context = {};
let head;
context.head = new Proxy({}, {
get(obj, prop) {
if (!head) {
head = {
htmlAttrs: {
// Include the properties
...obj.htmlAttrs,
lang: 'Fr'
}
}
}
if (prop === 'htmlAttrs') {
return `${JSON.stringify(head.htmlAttrs)}`
}
const text = prop in head ? head[prop].text() : ''
return text && prop.endsWith('Attrs') ? ` ${text}` : text
},
set(obj, prop, value, rec) {
return Reflect.set(...arguments);
}
})
context.head.htmlAttrs = {
key: true
}
console.log(context.head.htmlAttrs)
Related
I have a set of JSON objects having the wsDestAddress key, so how do I traverse the JSON objects or do a wild search for wsDestAddress key in present JSON objects to find the key is present or not and returning null or ""?
JSON Object #1
{
"gfutd": {
"wsRequestData": {
"wsDestAddress": ""
}
}
}
JSON Object #2
{
"igftd": {
"wsRequestData": {
"wsDestAddress": ""
}
}
}
JSON Object #3
{
"y7igfutd": {
"wsResponseData": {
"wsDestAddress": ""
}
}
}
JSON Object #4
{
"y7igptdf": {
"wsRequestData": {
"returnAddress": {
"wsDestAddress": ""
}
}
}
}
I know this code works fine
if (y7igfutd.wsRequestData.wsDestAddress == "" ||
igftd.wsRequestData.wsDestAddress == "" ||
y7igfutd.wsResponseData.wsDestAddress == "" ||
y7igfutd.wsRequestData.returnAddress.wsDestAddress == "") {
return "result"
}
But I want to do a wild search for wsDestAddress as the JSON keys search.
Here is an answer using object-scan. Your requirements were not entirely clear, but I'm sure you can easily adjust the below code to meet your needs.
// const objectScan = require('object-scan');
const data1 = { gfutd: { wsRequestData: { wsDestAddress: '' } } };
const data2 = { igftd: { wsRequestData: { wsDestAddress: '' } } };
const data3 = { y7igfutd: { wsResponseData: { wsDestAddress: '' } } };
const data4 = { y7igptdf: { wsRequestData: { returnAddress: { wsDestAddress: '' } } } };
const data5 = { y7igptdf: { wsRequestData: { returnAddress: { other: '' } } } };
const search = objectScan(['**.wsDestAddress'], {
filterFn: ({ value }) => value === '',
rtn: 'bool',
abort: true
});
console.log(search(data1));
// => true
console.log(search(data2));
// => true
console.log(search(data3));
// => true
console.log(search(data4));
// => true
console.log(search(data5));
// => false
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan#14.0.0"></script>
Disclaimer: I'm the author of object-scan
You can find the first item that has a "wsDestAddress" value of "" via:
const data = [
{ "y7igfutd" : { "wsResponseData" : { "wsDestAddress" : "" }}},
{ "igftd" : { "wsRequestData" : { "wsDestAddress" : "" }}},
{ "y7igfutd" : { "wsResponseData" : { "wsDestAddress" : "" }}},
{ "y7igptdf" : { "wsRequestData" : { "returnAddress" : { "wsDestAddress" : "" }}}}
];
// Adapted from: https://stackoverflow.com/a/40604638/1762224
const findValue = (object, key) => {
let value;
Object.keys(object).some(k => {
if (k === key) {
value = object[k];
return true;
}
if (object[k] && typeof object[k] === 'object') {
value = findValue(object[k], key);
return value !== undefined;
}
});
return value;
};
const oneMatches = (arr, key, value) =>
arr.some(item => findValue(item, key) === value);
const allMatches = (arr, key, value) =>
arr.every(item => findValue(item, key) === value);
console.log(oneMatches(data, 'wsDestAddress', '')); // Some = true
console.log(allMatches(data, 'wsDestAddress', '')); // Every = true
I have one object like below
let a = {
title: {
value:"developer"
}
publishedOn:{
month:{
value:"jan"
}
year:{
value:"2000"
}
}
and i want to convert it like below object
let b = {
title : "Developer"
publishedOn:{
month:"jan",
year:"2000"
}
}
Constrains are we don't know what properties are inside a variable
I have tried iterative method and i though its not the better way
please help me for better solution
function set(path, value) {
var schema = obj;
var pList = path.split('.');
var len = pList.length;
for(var i = 0; i < len-1; i++) {
var elem = pList[i];
if( !payload[elem] ) payload[elem] = {}
payload = payload[elem];
}
payload[pList[len-1]] = value;
console.log(payload);
}
Object.keys(this.formObject).forEach((key)=> {
if (Object.prototype.hasOwnProperty.call(this.formObject, key)) {
this.getPath(this.formObject[key],key).then((data:any)=>{
set(data.path, data.value);
});
}
});
}
async getPath(obj,path) { //publishedOn , month, yeaer
let value = "";
Object.keys(obj).forEach((key)=> {//month
if (Object.prototype.hasOwnProperty.call(obj, key)) {
if(key === "value"){
path = path;
value = obj[key]
}else{
path = path + "." + key; // publishedOn.month
value = obj[key]['value']; // june
}
}
});
return {path,value }
}
You could look ahead for a coming object and take the final value.
function omitLast(object) {
return Object.fromEntries(Object.entries(object).map(([key, value]) => [
key,
Object.values(value).every(item => item && typeof item === 'object')
? omitLast(value)
: Object.values(value)[0]
]));
}
let input = { title: { value: "developer" }, publishedOn: { month: { value: "jan" }, year: { value: "2000" } } };
result = omitLast(input);
console.log(result);
For old browsers.
function omitLast(object) {
return Object.keys(object).reduce(function (r, key) {
r[key] = Object.keys(object[key]).every(function (k) { return object[key][k] && typeof object[key][k] === 'object'; })
? omitLast(object[key])
: object[key][Object.keys(object[key])[0]];
return r;
}, {});
}
let input = { title: { value: "developer" }, publishedOn: { month: { value: "jan" }, year: { value: "2000" } } };
result = omitLast(input);
console.log(result);
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>
let's say that I have the current data object:
const human = {
name: '',
age: 0,
head: {
rightEye: '',
leftEye: '',
}
limbs: {
arms: '',
legs: '',
}
somethingElse: '',
}
I want to remove every empty key/value pairs. And this part I got it working with the following code:
const removeFalsy = (obj) => {
const newObj = {};
Object.keys(obj).forEach((prop) => {
if (obj[prop]) {
if (typeof obj[prop] === 'object') {
newObj[prop] = removeFalsy(obj[prop]);
} else {
newObj[prop] = obj[prop];
}
}
});
return newObj;
};
The thing is empty objects still stay in the main object. I want to remove every empty object from inside the main object in order to get the following result:
const human = {};
In place of my current results:
const human = {
head: {},
limbs: {},
}
What are my best options?
When recursively calling removeFalsy, only assign to newObj if the result of the recursive call has an object with at least one key:
const removeFalsy = (obj) => {
const newObj = {};
Object.keys(obj).forEach((prop) => {
if (obj[prop]) {
if (typeof obj[prop] === 'object') {
// change below:
const nonFalseyVal = removeFalsy(obj[prop]);
if (Object.keys(nonFalseyVal).length !== 0) {
newObj[prop] = nonFalseyVal;
}
// change above
} else {
newObj[prop] = obj[prop];
}
}
});
return newObj;
};
const human = {
name: '',
age: 0,
head: {
rightEye: '',
leftEye: '',
},
limbs: {
arms: '',
legs: '',
},
somethingElse: '',
}
const nonFalsyHuman = removeFalsy(human);
console.log(nonFalsyHuman);
Note that it might be more appropriate to use .reduce, and you can use Object.entries to get the key and the value immediately:
const removeFalsy = (obj) => {
return Object.entries(obj).reduce((a, [key, val]) => {
if (!val) return a;
if (typeof val === 'object') {
const nonFalseyVal = removeFalsy(val);
if (Object.keys(nonFalseyVal).length !== 0) {
a[key] = nonFalseyVal;
}
} else {
a[key] = obj[key];
}
return a;
}, {});
};
const human = {
name: '',
age: 0,
head: {
rightEye: '',
leftEye: '',
},
limbs: {
arms: '',
legs: '',
},
somethingElse: '',
}
const nonFalsyHuman = removeFalsy(human);
console.log(nonFalsyHuman);
You need to make following changes
Update if (typeof obj[prop] === 'object') { condition where you set value only if the object has some valid keys.
Update if (obj[prop]) { condition to allow other non-falsy values to enter the loop e.g. 0, etc.
const human = {name: '',age: 0,head: {rightEye: '',leftEye: ''},limbs: {arms: '',legs: ''},somethingElse: ''};
const removeFalsy = (obj) => {
const newObj = {};
Object.keys(obj).forEach((prop) => {
if (obj[prop] !== "") {
if (typeof obj[prop] === 'object') {
const temp = removeFalsy(obj[prop]);
if(Object.keys(temp).length) newObj[prop] = temp;
} else {
newObj[prop] = obj[prop];
}
}
});
return newObj;
};
console.log(removeFalsy(human));
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 }