How to modify a complex JSON Object in using Immutable - reactjs

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...

Related

React Native - Sort array based off words

Hey guys i have the following array:
Array [
Object {
"data": "Cat Man",
"id": "1",
},
Object {
"data": "Bat Girl",
"id": "2",
},
Object {
"data": "Mr Penguin",
"id": "3",
},
Object {
"data": "Cheeky Cheetah",
"id": "4",
},
]
I am going to take the users input in the form of a search bar, how can i sort the array based off the users input.
So lets say the user inputs
Bat g
the array would be sorted to:
Array [
Object {
"data": "Bat Girl",
"id": "2",
},
Object {
"data": "Cat Man",
"id": "1",
},
Object {
"data": "Mr Penguin",
"id": "3",
},
Object {
"data": "Cheeky Cheetah",
"id": "4",
},
]
How can I achieve this?
I have been searching around the array sort function:
Array.prototype.sort()
However I have only seen how to sort based off number comparisons I have never seen an array sorted based off string values like a search. Please could someone help me with this!
Here is function to search data using string text.
const searchItem = txt => {
let text = txt.toLowerCase();
let tracks = dataArray;
let filterTracks = tracks.filter(item => {
if (item.data.toLowerCase().match(text)) {
return item;
}
});
console.log('filterTracks', filterTracks);
};
Array Should be like this
var dataArray = [
{
data: 'Cat Man',
id: '1',
},
{
data: 'Bat Girl',
id: '2',
},
{
data: 'Mr Penguin',
id: '3',
},
{
data: 'Cheeky Cheetah',
id: '4',
},
];

Angular - Convert objects in a nested array into comma seapared values before binding to grid

below is part of my JSON response coming from an API
{
"totalCount": 2,
"customAttributes": [
{
"objectType": "OWNER",
"atrributeId": 215,
"attributeName": "DATELICENSEFIRSTISSUED",
"attributeDisplayName": "DATE LICENSE FIRST ISSUED",
"dataType": "DATE",
"inputValues": [],
"isGridEligible": "true",
"isInvoiceEligible": "false"
},
{
"objectType": "LOCATION",
"atrributeId": 217,
"attributeName": "DONOTRENEW",
"attributeDisplayName": "DO NOT RENEWS",
"dataType": "Value List",
"inputValues": [
{
"id": 5,
"value": "VEHICLELISTREQUIRED"
},
{
"id": 6,
"value": "STATESWITHRECIPROCITY"
}
],
"isGridEligible": "true",
"isInvoiceEligible": "false"
}
]
}
Here, I am binding customAttributes as grid data.
this.customFieldsService.getCustomFields(this.columnList, this.pageNumber, this.pageSize, null).subscribe(res => {
if(res){
this.cfData = res;
this.gridData = {
data: this.cfData.customAttributes,
total: this.cfData.totalCount
}
}
});
Here, my problem is with inputValues column, which comes as an array of objects. I need to convert it to comma seaparated values and then bind to grid data like
"inputValues": ["VEHICLELISTREQUIRED" "STATESWITHRECIPROCITY"]
I can ignore the "id" property as we are not using it at angular side. I tried using join method but not able to solve it within the nested array. Please suggest. Thanks.
In typescript it can be done with:
const joined: string = customAttribute.inputValues
.map(x => x.value) // [{value: 'VEHICLELISTREQUIRED'}, {value: 'STATESWITHRECIPROCITY'}]
.join(' ') // "VEHICLELISTREQUIRED" "STATESWITHRECIPROCITY"
const putIntoArray = [joined]; // ["VEHICLELISTREQUIRED" "STATESWITHRECIPROCITY"]
Of course you can put the joined string immediately into an array.

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);

How to Join Multiple Arrays inside filter function of Arrays in Typescript

I am using Typescript in an Angular/Ionic project. I have an array of users that contain an array of skills. I have to filter users based on their online status as well as skills.
[
{
"id": 1,
"name": "Vikram Shah",
"online_status": "Online",
"skills": [{
"id": 2,
"title": "CSS"
},
{
"id": 3,
"title": "JavaScript"
},
{
"id": 4,
"title": "Python"
}
]
},
{
"id": 1,
"name": "Abhay Singh",
"online_status": "Online",
"skills": [{
"id": 1,
"title": "HTML"
},
{
"id": 2,
"title": "CSS"
},
{
"id": 3,
"title": "JavaScript"
},
{
"id": 4,
"title": "Python"
}
]
},
{
"id": 1,
"name": "Test Oberoi",
"online_status": "Online",
"skills": [{
"id": 1,
"title": "HTML"
},
{
"id": 2,
"title": "CSS"
},
{
"id": 3,
"title": "JavaScript"
},
{
"id": 4,
"title": "Python"
}
]
}
]
This is how all skills look like
this.skill_types = [
{"id":8,"title":"Cleaner", checked:false},
{"id":7,"title":"Painter", checked:false},
{"id":6,"title":"Plumber", checked:false},
{"id":5,"title":"Carpenter", checked:false},
{"id":4,"title":"Advisor", checked:false},
{"id":3,"title":"Team Leader", checked:false},
{"id":2,"title":"Management", checked:false},
{"id":1,"title":"Administrator", checked:false}
];
This array contains the IDs of skills that I want to filter
filterArr = [1, 3, 6];
This solution is almost working as expected. It is filtering well based on two criteria together.But not sure how to add condition for second filtering. The second filter should apply only if filterArr is not empty.
return this.items = this.items.filter((thisUser) => {
return thisUser.online_status.toLowerCase().indexOf(onlineStatus.toLowerCase()) > -1 &&
thisUser.skills.some(c => this.filterArr.includes(c.id))
});
The issue I am facing with code above is When there is no skill selected in the filter criteria, I would like to display all users. But it is not working that way. The logic here is to not apply any filter when the size of selected skills (filter condition) is greater than zero. So I tried this way....which looks similar to the way above...but this makes everything worse.
let filteredByStatus = [];
filteredByStatus = this.items.filter((thisUser) => {
return thisUser.online_status.toLowerCase().indexOf(onlineStatus.toLowerCase()) > -1
});
//Condition can be applied if filtering is separated
let filteredBySkills = [];
filteredBySkills = this.items.filter((thisUser) => {
return thisUser.skills.some(c => this.filterArr.includes(c.id))
});
//Expecting to join results from multiple filters
return this.items = filteredByStatus.concat(filteredBySkills);
But this is not working at all. Not sure what wrong is there. I am looking for a solution that enables to join arrays of similar objects without duplicating them.
Don't think you need to join arrays for your filtering. You can use something like rxjs filter.
return from(this.items)
.pipe(
filter(user => {
return user.online_status.toLowerCase().indexOf(onlineStatus.toLowerCase()) > -1
&& user.skills.some(c => filterArr.includes(c.id));
})
);
Or if you like to split it up you can just change it to like:
return from(this.items)
.pipe(
filter(user => user.online_status.toLowerCase().indexOf(onlineStatus.toLowerCase()) > -1),
filter(user => user.skills.some(c => filterArr.includes(c.id)))
);
Stackblitz: https://stackblitz.com/edit/angular-pk3w8b
You can tweak your condition a bit and place !this.filterArr.length in your condition (in terms of OR condition AND with user status) to make your whole condition gets true so that user gets filter.

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;
});

Resources