I created this function:
const demoD = (
obj,
toChange,
newV,
) => {
return Object.keys(obj).reduce((acc, key) => {
if (typeof obj[key] === 'object') {
demoD(obj[key], toChange, newV);
}
acc[key] = obj[key] === toChange ? newV : obj[key]
return acc
}, {})
}
const obj = {
name: '',
age: '687',
demo: {
test: ''
}
}
console.log(demoD(obj, '', null))
The idea of this function is to change a value from the object with a new one, and it should run recursivelly. I expect this result:
const obj = {
name: null',
age: '687',
demo: {
test: null'
}
}
But i don't get this result, and the test still unchanged. Question: How to fix and what is the issue?
If you want to apply change to the original object in place:
const demoD = (
obj,
toChange,
newV,
) => {
return Object.keys(obj).reduce((acc, key) => {
if (typeof obj[key] === 'object') {
demoD(obj[key], toChange, newV);
}
acc[key] = obj[key] === toChange ? newV : obj[key]
return acc
}, obj) // 👈 send in obj here
}
If you don’t want to mutate your original object, then it should be:
const demoD = (
obj,
toChange,
newV,
) => {
return Object.keys(obj).reduce((acc, key) => {
if (typeof obj[key] === 'object') {
acc[key] = demoD(obj[key], toChange, newV)
} else {
acc[key] = obj[key] === toChange ? newV : obj[key]
}
return acc
}, {})
}
Related
i have an interesting example of code that's not working like i'm expected.
I really dont understand why my obj wouldnt proxy.
I'm expect that obj ill proxy via link, but it's not. Can anyone explain how it's works and what I don't understand? Thank you!
let obj = {
foo: "123"
};
function test(fn, object) {
object = new Proxy(object, {
get(target, key) {
console.log('get');
return target[key];
},
set(target, key, value) {
console.log('set');
target[key] = value;
return true;
}
});
fn();
}
test(() => {
obj.foo = "helloworld";
console.log(obj.foo);
}, obj);
UPD: i want to assign object to proxy variable ONLY through arguments can i?
Either assign the proxy to obj
let obj = {
foo: "123"
};
function test(fn, object) {
obj = new Proxy(object, {
get(target, key) {
console.log('get');
return target[key];
},
set(target, key, value) {
console.log('set');
target[key] = value;
return true;
}
});
fn();
}
test(() => {
obj.foo = "helloworld";
console.log(obj.foo);
}, obj);
Or pass the proxy as an argument
let obj = {
foo: "123"
};
function test(fn, object) {
const o = new Proxy(object, {
get(target, key) {
console.log('get');
return target[key];
},
set(target, key, value) {
console.log('set');
target[key] = value;
return true;
}
});
fn(o);
}
test((o) => {
o.foo = "helloworld";
console.log(o.foo);
}, obj);
What causes the ff issue ? Cannot assign to read only property '0' of object '[object Array]' ?
Any idea would be appreacited. Thanks.
#ts code snippet
const [RegionalList, setRegionalList] = useState<IRegionalList[]>(RegionalListData);
const setEmailValue = (event: any, regionalId: number, index: number) => {
setRegionalList((prevState: IRegionalList[]) => {
const newState = prevState.map((prop: IRegionalList) => {
if (prop.id === regionalId) {
prop.emails[index] = { emailAddress: event.target.value, id: null };
return { ...prop };
}
return prop;
});
return newState;
});
}
here is the way that I suggest :
const [RegionalList, setRegionalList] = useState<IRegionalList[]>(RegionalListData);
const setEmailValue = (event: any, regionalId: number, index: number) => {
setRegionalList((prevState: IRegionalList[]) => {
const newState = prevState.map((prop: IRegionalList) => {
if (prop.id === regionalId) {
return { ...prop,emails:[...prop.emails.filter( (_,i)=>i !== index ),{ emailAddress: event.target.value, id: null }] }
}
return prop;
});
return newState;
});
}
and if you care about order of your list you can do this :
const setEmailValue = (event: any, regionalId: number, index: number) => {
setRegionalList((prevState: IRegionalList[]) => {
const newState = prevState.map((prop: IRegionalList) => {
if (prop.id === regionalId) {
let emails = prop.emails;
emails[index] = { emailAddress: event.target.value, id: null };
return { ...prop,emails }
}
return prop;
});
return newState;
});
}
please let me know if it fixed your problem
I want to find the first array in an object in Javascript. However my functions cause an error:
el is undefined
el contains the object that looks like this:
data = {
foo: {
bar: [{object a},
{object b},
{object c}
]
}
}
let el = data;
el = this.searchArray(el);
el.forEach(element => {
console.log(element);
let siblingData = this.injectFilterParameters(element);
});
//here is unimportant code
searchArray(obj) {
if (Array.isArray(obj)) {
return obj;
} else {
Object.keys(obj).forEach(key => {
if (Array.isArray(obj[key])) {
return obj[key];
} else {
return this.searchArray(obj[key]);
}
})
}
}
const data = {
foo: {
bar: [
{ object: 'a' },
{ object: 'b' },
{ object: 'c' }
]
}
}
console.log(findArray(data))
function findArray(data: unknown): unknown[] | undefined {
if (Array.isArray(data)) {
return data
}
if (typeof data !== 'object') {
return undefined
}
const object = data as Record<string, unknown>
for (const key of Object.keys(object)) {
const value = object[key]
const valueSearchResult = findArray(value)
if (valueSearchResult != undefined) {
return valueSearchResult
}
}
return undefined
}
I'm trying to solve compiler error " Object is possibly 'undefined' "
const destinationColumnIndex = (): number => {
if (typeof result.destination === 'undefined') {
return 0;
}
return boardData.findIndex(
(column) => column.id === Number(result.destination.droppableId)
);
};
but typescript compiler still tells me that "result.destination" may be undefined.
I have tried also:
if (result.destination === undefined) {
return 0;
}
and:
if (!result.destination) {
return 0;
}
and:
if (!result || typeof result.destination === 'undefined') {
return 0;
}
and nothing works. Even thought it may be some bug so i restarted VS Code but there are still the same error.
EDIT - MORE CODE:
const onDragEnd = async (result: DropResult) => {
if (!result.destination) {
return;
}
const sourceColumnIndex = (): number =>
boardData.findIndex(
(column) => column.id === Number(result.source.droppableId)
);
const destinationColumnIndex = (): number => {
if (typeof result === 'undefined' || result.destination === undefined) {
return 0;
}
return boardData.findIndex(
(column) => column.id === Number(result.destination.droppableId)
);
};
it's function inside of react component
You should just do:
if (result === undefined || result?.destination === undefined) {
return 0;
}
Checking typeof is not a good way to check for undefined.
or
if (!result || result?.destination === undefined) {
return 0;
}
UPDATE
try this:
const onDragEnd = (result: DropResult) => {
if (!result || !result.destination) {
return;
}
const sourceColumnIndex = (): number =>
boardData.findIndex(
(column) => column.id === Number(result.source?.droppableId)
);
const destinationColumnIndex = (): number => {
if (!result || !result.destination) {
return 0;
}
return boardData.findIndex(
(column) => column.id === Number(result.destination?.droppableId)
);
};
}
I build following method that change the structure of the input objects. It works but I would like to make it immutable.
function formatObj(obj: Object) {
const keys = Object.keys(obj)
keys.forEach((key) => {
const value = obj[key]
if (value === null || value === undefined) {
return
}
else if (key === 'size') {
obj[key] = { value, min: 0, max: 0 }
}
else if (typeof value === 'object') {
formatObj(obj[key])
}
})
}
I tried this but it returns a list of undefined...
function formatObj(obj: Object) {
const keys = Object.keys(obj)
const r = keys.map((key) => {
const value = obj[key]
if (value === null || value === undefined) {
return { key: value }
}
else if (key === 'size') {
return { key: { value, min: 0, max: 0 } }
}
else if (typeof value === 'object') {
return formatObj(obj[key])
}
})
return r
}
Why? How can I solve?
The idiom you're looking for is Object.fromEntries(Object.entries(...).map...):
let mapObject = (obj, fn) => Object.fromEntries(
Object.entries(obj).map(([k, v]) => fn(k, v))
);
//
let test = {
a: 0,
size: 123,
sub: {
b: null,
size: 456
}
}
let transformer = (key, value) => {
if(key === 'size')
return [key, { value, min: 0, max: 0 }];
if(!value || typeof value !== 'object')
return [key, value];
return [key, mapObject(value, transformer)]
}
let test2 = mapObject(test, transformer)
console.log(test2)
One drawback of this is that you have to have an external transformer variable to be able to reapply it. A nicer approach would be to define the transformer inside the mapper and pass it around as an argument. Also, it won't hurt to make it a bit more generic:
function transform(obj, fn) {
function transformer(x) {
if (!x || typeof x !== 'object')
return x;
if (Array.isArray(x))
return x
.map((v, k) => fn(k, v, transformer))
.filter(x => x !== void 0)
.map(x => x[1]);
return Object.fromEntries(
Object.entries(x)
.map(([k, v]) => fn(k, v, transformer))
.filter(x => x !== void 0));
}
return transformer(obj);
}
//
let test = {
a: 0,
size: 123,
removeMe: 123,
renameMe: 456,
sub: {
b: null,
size: 456,
removeMe: 1230,
renameMe: 4560,
sub2: {
foo: ['bar', 'baz', {size: 798}]
}
}
}
let test2 = transform(test, (key, value, transformer) => {
// return undefined to remove a key
if (key === 'removeMe')
return;
// return a new key
if (key === 'renameMe')
return ['renamed!', value];
// return a new value
if (key === 'size')
return [key, {value, min: 0, max: 0}];
// keep transforming
return [key, transformer(value)]
});
document.write('<pre>' + JSON.stringify(test2,0,4))
Object.fromEntries is relatively new, but can be trivially polyfilled.
result of a Array map function is a list. In this case you probably want to use reduce function to make result object again. It would help better to understand if you provided some sample input and output data.
function formatObj(obj: Object) {
const keys = Object.keys(obj)
const r = keys.reduce((resultObj, key) => {
const value = obj[key]
if (value === null || value === undefined) {
return { ...resultObj, [key]: value }
}
else if (key === 'size') {
return { ...resultObj, [key]: { value, min: 0, max: 0 } }
}
else if (typeof value === 'object') {
return { ...resultObj, [key]: formatObj(obj[key]) }
}
}, {})
return r
}