How to encapsulate object fields to be in array - arrays

I have an object that can be with different properties (arrays/objects/etc).
I want to convert the object to be with each sub field encapsulated by array.
For example:
"head": {
"text": "Main title",
"sub": {
"value": "next"
},
"place": "secondary"
}
the head field including an object.
I want the object to be encapsulate in array like this:
"head": [{
"text": "Main title",
"sub": {
"value": "next"
},
"place": "secondary"
}]
I figured out this is the possibility to keep the structure same for every item.
I also tryied to do so with interface but it made me problems since sometimes it's object and sometimes not so I want to keep the structure.
I would like to hear more if there's a better way to convert the object to a proper interface.
Thanks!

This will recursively check each value and make it an array if it isn't. Excluding keys you put in the keysToSkip array.
const obj = {
"head": {
"text": "Main title",
"sub": {
"value": "next"
},
"place": "secondary"
},
"alreadyArray": [
"val", "val2"
]
}
const keysToSkip = ["value"]
let depthFirstLoop = (obj) => {
Object.keys(obj).forEach((key) => {
if (typeof obj[key] === 'object' && obj[key] !== null) {
depthFirstLoop(obj[key]);
}
if (!Array.isArray(obj[key]) && !keysToSkip.includes(key)) {
obj[key] = [obj[key]]
}
});
};
depthFirstLoop(obj)
https://jsfiddle.net/9p7k64ec/26/

Generally you shouldn't change an object as you iterate over it. Better to create a new object.
const obj = {
"head": {
"text": "Main title",
"sub": {
"value": "next"
},
"place": "secondary"
}
}
var newObj = {}
for( key in obj ){
newObj[key] = [obj[key]]
}

Related

Please tell me how to resolve a type error

I'm writing a program that turns two data into a new one.
Each of the data comes from an API, so the undefined case must be considered.
but,
item.id === message.sender.userId
A type error occurs in userId in the section.
I want to resolve this type error.
I want to solve it by a means that does not change the type or data.
Is this possible?
const newMessages = React.useMemo(() => {
if (messages === undefined || userItems === undefined) return [];
return messages.map(message => {
if (message.sender.type === "user" && message.sender.userId) {
const user = userItems.find(item => item.id === message.sender.userId);
if (user) message.sender = { ...message.sender, icon: user.image };
}
return message;
});
}, [messages, userItems]);
Here are the two data I'm getting, and the type of one:
type IMessage = {
sender:
| {
type: "user";
userId: number;
}
| {
type: "admin";
adminId: number;
};
body:
| {
type: "text";
text: "text";
}
| {
type: "image";
text: string;
image: string;
};
};
const messages: IMessage[] =
[
{
"sender": {
"type": "admin",
"adminId": 789
},
"body": {
"type": "image",
"text": "abcde",
"image": "https://imageUrl"
},
},
{
"sender": {
"type": "user",
"userId": 10
},
"body": {
"type": "text",
"text": "Hello!"
},
},
{
"sender": {
"type": "user",
"userId": 13
},
"body": {
"type": "image",
"text": "Hello my friend!",
"image": "https://imageUrl"
},
},
]
const userItems =
[
{
"id": 10,
"name": "kenny",
"image": "https://imageUrl",
"age": 23,
"gender": "M",
},
{
"id": 13,
"name": "Jon",
"image": "https://imageUrl",
"age": 32,
"gender": "M",
}
]
const user = userItems.find(item => item.id === message.sender.userId);
You and i know that this function is going to be called right away, but typescript does not. In general, a callback function could be called at any time, synchronously or asynchronously, and nothing in the type information specifies that. As a result, typescript cannot guarantee that message.sender will still be a user when the callback gets called.
To fix this, assign the value to a const, so typescript can know for sure it won't change.
if (message.sender.type === "user" && message.sender.userId) {
const userId = message.sender.userId
const user = userItems.find(item => item.id === userId);
// ...
P.S:
body:
| {
type: "text";
text: "text";
}
You probably meant to do text: string

Conversion of list of JSON array to a single object in Angular

I have an array list which needs to be converted to a single object with few of the values from array list using TypeScript in Angular 8. Below is the array:
"arrayList": [{
"name": "Testname1",
"value": "abc"
},
{
"name": "Testname2",
"value": "xyz"
}
]
This needs to be converted to the below format,
data: {
"Testname1": "abc",
"Testname2": "xyz",
}
No matter how much i try, i end up creating a list instead of a single object. Can you please help on the same?
You can use as follows,
var arr = [
{
"name": "Testname1",
"value": "abc"
},
{
"name": "Testname2",
"value": "xyz"
}
];
var result = {};
for (var i = 0; i < arr.length; i++) {
result[arr[i].name] = arr[i].value;
}
console.log(result);
Try with using .reduce() as the following:
const arrayList = [{ "name": "Testname1", "value": "abc" }, { "name": "Testname2", "value": "xyz" }];
const data = arrayList.reduce((a, {name, value}) => {
a[name] = value;
return a;
}, {});
const result = { data };
console.log(result);
Use Array.map() to get a list of [name, value] entries, then use Object.fromEntries() to convert to an object:
const arrayList = [{ "name": "Testname1", "value": "abc" }, { "name": "Testname2", "value": "xyz" }];
const result = Object.fromEntries(arrayList.map(({ name, value }) => [name, value]));
console.log(result);
Please use the below code
const rawData = {
"arrayList": [{
"name": "Testname1",
"value": "abc"
},
{
"name": "Testname2",
"value": "xyz"
}
]
};
const updatedData = {
data: {}
};
for (const item of rawData["arrayList"]) {
updatedData.data[item.name] = item.value;
}
console.log(updatedData);

Updating state of deep object value in React/Redux using immutable.js

I have this pretty deeply nested state array and need to update the Hours field by Employee, Task, and Week. I've attempted numerous ways to do this with Immutable but not having success, any help?
Here is an example of my data :
[{
"Employee": "John Doe",
"Other Data": "test",
"Tasks": [{
"AccessType": "Confidential",
"DueDate": "2016-02-26 23:59:59",
"taskId": "3",
"TaskTitle": "testTitle",
"Weeks": {
"2016-10-10": {
"Hours": "3"
}
}
}]
}, {
"Employee": "Bill Der",
"Other Data": "test",
"Tasks": [{
"AccessType": "Confidential",
"DueDate": "2016-02-26 23:59:59",
"taskId": "3",
"TaskTitle": "testTitle",
"Weeks": {
"2016-10-10": {
"Hours": "3"
}
}
}]
}]
You are missing a bunch of information for me to fully answer this for you, but I can show you how I would do something like this otherwise.
You can take advantage of all the functions immutable js provides you with. So lets say you have an object with the information needed to mutate your immutable object, something like this :
var changeHours = {
"Employee": "John Doe",
"TaskTitle": "testTitle",
"Week": '2016-10-10',
"Hours": "5"
}
And we have a basic state like you have there set up like this :
var myState = Immutable.fromJS([{
"Employee": "John Doe",
"Tasks": [{
"AccessType": "Confidential",
"DueDate": "2016-02-26 23:59:59",
"taskId": "3",
"TaskTitle": "testTitle",
"Weeks": {
"2016-10-10": {
"Hours": "3"
}
}
}]
}]);
Note: I did not add more the the arrays, but we will map over them so they will be taken into account.
You can use immutables map to iterate over and find the items you are looking for, something like this :
var newstate = myState.map((k, v) => {
if (k.get('Employee') === changeHours.Employee) {
return k.get('Tasks').map((k, v) => {
if (k.get('TaskTitle') === changeHours.TaskTitle) {
return k.setIn(['Weeks', changeHours.Week, 'Hours'], changeHours.Hours);
}
return k;
})
return k;
}
return k;
});
To see it in action - http://fiddle.jshell.net/djj6u8xL/63/ . I am iterating over each array level with map and finding the correct node by checking based on our changeHours object and immutables get, then once I am at the right level I just use setIn. You can use updateIn as well, it just depends on your scenario.
In the future, please provide all the information for your question, not just a picture of the data, it will be much easier to help you :) (and not have to type out the data structure manually).
Edit: Update based on comment - http://fiddle.jshell.net/qxbq1nq3/9/
the code :
function newTasks(k) {
return k.get('Tasks').map((k, v) => {
if (k.get('TaskTitle') === changeHours.TaskTitle) {
return k.setIn(['Weeks', changeHours.Week, 'Hours'], changeHours.Hours);
}
return k;
});
}
var newstate = myState.map((k, v) => {
if (k.get('Employee') === changeHours.Employee) {
return k.set('Tasks', newTasks(k));
}
return k;
});

How to modify a complex JSON Object in using Immutable

I have below JSON and wanted to update the value depending on Aid, Bid and Cid using Immutable.js
e.g.
Below input provided.
Aid= A, Bid = 1, Cid= 4, NewValue = 'FOUR'
If above input is provided the value "One" needs to be changed to "FOUR"
let sampleJson = {
Aid: 'A', detail:"sample", list: [
{
"Bid": "1",
"group": [
{
"name": "Group A",
"Cid": "4",
"value": "One"
},
{
"name": "Group A",
"Cid": "41",
"value": "1"
},
]
},
{
"Bid": "2",
"group": [
{
"name": "Group A",
"Cid": "4",
"value": "1"
},
{
"name": "Group A",
"Cid": "4",
"value": "1"
},
]
};
I was able to access the value using below code. How can i return the entire JSON with updated value?
let variale = Immutable.fromJS(sampleJson).
getIn(['list']).
find(allocation => allocation.get("Bid") === "1").
getIn(['group']).
find(fun => fun.get("Cid") === "4").set('value',"FOUR");
Anyone has any suggestions on how to resolve this problem?
I think you can try to do this like so:
let immutable = Immutable.fromJS(sampleJson);
immutable = immutable.setIn(['list', 0, 'group', 0, 'value'], 'FOUR');
This monstrosity is how I would do it:
const newData = originalData.update('list', list => {
const itemIndex = list.findIndex(item => item.get('Bid') === '2');
return list.update(itemIndex, listItem => {
return listItem.update('group', groupList => {
const groupIndex = list.findIndex(group => group.get('Cid') === '4');
return groupList.update(groupIndex, group => {
return group.set('value', 'FOUR');
});
});
});
});
https://jsbin.com/latupo/7/edit?html,js,console
Personally I stopped using Immutable, I always found it a bit painful (not to mention those docs!). I now use redux and good old cloning to not mutate state. Less performant in theory but if you've got nothing that runs over a few milliseconds anyway, save yourself the trouble...

ForEach Loop JSON AngularJS Object in Object

I am very new to AngularJS and I am trying to learn how to get deeper into a JSON object that has objects inside of objects and sometimes even arrays. This is a "simplified" version I am working with and I hope it will help me get a basic understanding so I can do the rest on my own.
json
values = {
"profile": {
"fields": {
"number-of-fields": "700",
"inside": [
"test1",
"test2"
],
"type": "test",
"values": "450"
}
},
"id": "12312312333645"
}
code
angular.forEach(values, function(value, key) {
console.log(key + ': ' + value);
// I know I need to loop inside of each object I beleieve
});
http://jsfiddle.net/ygahqdge/184/
The basics
Traverse object properties with a dot ., traverse array indexes with an index reference, [0|1|2|etc.].
What about your object?
var yoObject = {
"profile": {
"fields": {
"number-of-fields": "700",
"inside": [
"test1",
"test2"
],
"type": "test",
"values": "450"
}
},
"id": "12312312333645"
}
Get the inside values:
// object object object array
yoObject.profile.fields.inside.map(console.log, console) // ["test1", "test2"]
Get the id:
// object property
yoObject.id // "12312312333645"
Get all properties of the fields object:
Object.keys(yoObject.profile.fields) // ['number-of-fields', 'inside', 'type', 'values']
Get all values of the properies from above:
fields = yoObject.profile.fields
Object.keys(fields).map(key => console.log(fields[key])) // ["700", ["test1", "test2"], "test", "450"] // Note: Order isn't guaranteed
Just play about with things. Throw the object in the console and start to manually traverse it. Then try to loop over things.
Have fun!
Note: I tested none of that! :P
this is a question in regards on the right way to loop deep in JSON
objects – #user2402107
There's no right way. Sometimes you'll need to be fully dynamic, other times you can hardcode paths into nested properties and values.
Fiddle-Diddle
Nest as many times as you need:
angular.forEach(values, (value, key) => {
console.log("Value for", key, ":", value);
angular.forEach(value, (value, key) => {
console.log("Value for", key, ":", value);
angular.forEach(value, (value, key) => {
console.log("Value for", key, ":", value);
})
})
});
You can log the whole object to console. By using F12 tool, you can browse the object in the browser.
console.log(objectName);
angular.forEach works on arrays. lets suppose you have an array of objects as this
var values = [{
"profile": {
"fields": {
"number-of-fields": "700",
"interpertation": [
"whenever this is ready"
],
"type": "test",
"values": "450"
}
},
"id": "12312312333645"
},
{
"profile": {
"fields": {
"number-of-fields": "700",
"interpertation": [
"whenever this is ready"
],
"type": "test",
"values": "450"
}
},
"id": "12312312333645"
}]
you can explore each object and its properties like this
angular.forEach(values, function(value, key) {
console.log(value.profile.fields.values);
});
you can use . notation to access propertes

Resources