Object.keys() and find - reactjs

Struggling to understand why I get an error when I try to use ES6 .find on this data below. I'm trying to get the record with id number 3.
{
{id:10,title:'Dairy & Eggs'}
{id:7,title:'Laundry & Househo,}
{id:9,title:'Bakery'}
{id:8,title:'Fresh Food'}
{id:4,title:'Frozen Food'}
{id:6,title:'Health & Beauty'}
{id:3,title:'Food Cupboard'}
{id:5,title:'Drinks'}
{id:2,title:'Chilled Food'}
}
I tried
const category = categories.find(function (category) { return category.id === 3; }
console.log(category)
and
const category = categories.filter(category => category.id === 3)
console.log(category)
Any help is appreciated.

Array.filter() and Array.find() works over array not on object.
Either you need to change your Data to Array of Objects as
[
{id:10,title:'Dairy & Eggs'},
{id:7,title:'Laundry & Househo'},
{id:9,title:'Bakery'},
{id:8,title:'Fresh Food'},
{id:4,title:'Frozen Food'},
{id:6,title:'Health & Beauty'},
{id:3,title:'Food Cupboard'},
{id:5,title:'Drinks'},
{id:2,title:'Chilled Food'}
]
DEMO
var categories = [
{
"id": 10,
"title": "Dairy & Eggs"
},
{
"id": 7,
"title": "Laundry & Househo"
},
{
"id": 9,
"title": "Bakery"
},
{
"id": 8,
"title": "Fresh Food"
},
{
"id": 4,
"title": "Frozen Food"
},
{
"id": 6,
"title": "Health & Beauty"
},
{
"id": 3,
"title": "Food Cupboard"
},
{
"id": 5,
"title": "Drinks"
}
];
const category = categories.filter(category => category.id === 3) ;
console.log(category)

Related

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.

how to group the array of data based on multiple values?

I want to group the data based on the type and type_id
Here is the array
var addArray = [
{
"id": 24,
"language_id": 3,
"type": "service",
"type_id": 2,
"key": "service seeker",
"value": " need service"
},
{
"id": 23,
"language_id": 3,
"type": "service",
"type_id": 2,
"key": "phone",
"value": "phone number"
},
{
"id": 24,
"language_id": 3,
"type": "service",
"type_id": 7,
"key": "tester",
"value": "service tester"
}
{
"id": 19,
"language_id": 3,
"type": "offer",
"type_id": 4,
"key": "source",
"value": "resource"
}
]
I have tried let result = _.groupBy(addArray,'type') it is grouping the data based on type but I need to group by type as well as type_id
Expected output
If you need the a flat grouping based on two or more properties, use the _.groupBy() callback to combine the properties to a string:
const addArray = [{"id":24,"language_id":3,"type":"service","type_id":2,"key":"service seeker","value":" need service"},{"id":23,"language_id":3,"type":"service","type_id":2,"key":"phone","value":"phone number"},{"id":24,"language_id":3,"type":"service","type_id":7,"key":"tester","value":"service tester"},{"id":19,"language_id":3,"type":"offer","type_id":4,"key":"source","value":"resource"}]
const result = _.groupBy(addArray, o => `${o.type}-${o.type_id}`)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
If you need a multi level grouping, start by grouping by the type, then map the groups with _.values(), and group them again by type_id:
const { flow, partialRight: pr, groupBy, mapValues } = _
const fn = flow(
pr(groupBy, 'type'),
pr(mapValues, g => groupBy(g, 'type_id'))
)
const addArray = [{"id":24,"language_id":3,"type":"service","type_id":2,"key":"service seeker","value":" need service"},{"id":23,"language_id":3,"type":"service","type_id":2,"key":"phone","value":"phone number"},{"id":24,"language_id":3,"type":"service","type_id":7,"key":"tester","value":"service tester"},{"id":19,"language_id":3,"type":"offer","type_id":4,"key":"source","value":"resource"}]
const result = fn(addArray)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

add to array if not already available Typescript

I have a two arrays:
Users [
{ "id": 0, "name": "Scott" },
{ "id": 0, "name": "Jan" },
{ "id": 0, "name": "Jack" },
]
Users2Add [
{ "id": 0, "name": "Scott" },
{ "id": 0, "name": "Andy" },
{ "id": 0, "name": "John" },
]
I want to check if new users in Users2Add are already in Users array. If yes don't push(add to array) else add the new User(From User2Add) to Users array. Like:
forEach(var u in Users2Add ) {
if(!(Users.containts(x => x.id == User2Add.idx))) Users.push(u);
}
The problem is that there's no straightforward way to check object equality in JS, and of course:
{a: 1} === {a: 1} //false
A possible solution is to use lodash:
Users2Add.forEach(user => {
if (!Users.some(existingUser = > _.isEqual(existingUser, user))) {
Users.push(user);
}
});

Angularjs Splice in Nested Array

Hi can somebody help Removing element from nested json array like this
JSON
[{
"id": 1,
"name": "Furniture & Fixture",
"choice": {
"0": {
"req_goods": "table",
"qty": "10"
},
"1": {
"req_goods": "chair",
"qty": "5"
}
}
}, {
"id": 2,
"name": "Miscellaneous Property",
"choice": {
"0": {
"req_goods": "Office Rent",
"qty": "1"
}
}
}]
here how do I remove choice 1 of id 1 .
HTML
<div ng-repeat="cb in capital_budgets">
<div ng-repeat="choice in choices[$index]">
<input ng-model="cb.choice[$index].req_goods">
<input ng-model="cb.choice[$index].qty">
<button ng-hide="$first" ng-click="removeChoice($parent.$index,$index)">-</button>
</div>
<button ng-click="addNewChoice($index)">+</button>
</div>
JS
$scope.capital_budgets = [{"id":1,"name":"Furniture & Fixture"},
{"id":2,"name":"Miscellaneous Property"}];
$scope.choices = [{}];
$scope.choices[0] = [{}];
$scope.choices[1] = [{}];
$scope.choices[2] = [{}];
$scope.choices[3] = [{}];
$scope.choices[4] = [{}];
$scope.addNewChoice = function(id) {
$scope.choices[id].push({});
};
$scope.removeChoice = function(parent_id, id) {
$scope.choices[parent_id].splice(id, 1);
};
The Above removeChoice() remove last element but I want to remove the element that user choose to remove. please help i have been trying from 2 days.
You can make 'choice' of the array type as follows and use the index of the particular choice in the ng-repeat directive to remove the choice from the choices array.
angular
.module('demo', [])
.controller('DefaultController', DefaultController);
function DefaultController() {
var vm = this;
vm.items = [
{
"id": 1,
"name": "Furniture & Fixture",
"choices": [
{
"id": 1,
"req_goods": "table",
"qty": "10"
},
{
"id": 2,
"req_goods": "chair",
"qty": "5"
}]
}, {
"id": 2,
"name": "Miscellaneous Property",
"choices": [
{
"id": 1,
"req_goods": "Office Rent",
"qty": "1"
}]
}];
vm.removeChoice = removeChoice;
vm.addChoice = addChoice;
function removeChoice(itemId, index) {
for (var i = 0; i < vm.items.length; i++) {
if (vm.items[i].id === itemId) {
vm.items[i].choices.splice(index, 1);
break;
}
}
}
function addChoice(index) {
var id = vm.items[index].choices.length + 1;
vm.items[index].choices.push({
id: id,
req_goods: "",
qty: 0
});
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="demo">
<div ng-controller="DefaultController as ctrl">
<div ng-repeat="item in ctrl.items">
<h3>{{item.name}}</h3>
<div ng-repeat="choice in item.choices">
<input type="text" ng-model="choice.req_goods" />
<input type="text" ng-model="choice.qty" />
<button type="button" ng-click="ctrl.removeChoice(item.id, $index)">Remove</button>
</div>
<button type="button" ng-click="ctrl.addChoice($index)">Add</button>
</div>
</div>
</div>
You can remove choice "1" of id 1 using the below code snippet.
var json = [
{
"id": 1,
"name": "Furniture & Fixture",
"choice": {
"0": {
"req_goods": "table",
"qty": "10"
},
"1": {
"req_goods": "chair",
"qty": "5"
}
}
}, {
"id": 2,
"name": "Miscellaneous Property",
"choice": {
"0": {
"req_goods": "Office Rent",
"qty": "1"
}
}
}];
function removeChoice(json, parentId, choice) {
for (var i = 0; i < json.length; i++) {
if (json[i].id === parentId) {
delete json[i].choice[choice];
break;
}
}
}
removeChoice(json, 1, "1");
console.log(json);
If you want the the choice also to be of the same type as its parent element i.e. an array you could change your JSON as follows and do as shown in the below code snippet to remove a choice from the JSON
var json = [
{
"id": 1,
"name": "Furniture & Fixture",
"choices": [
{
"id": 1,
"req_goods": "table",
"qty": "10"
},
{
"id": 2,
"req_goods": "chair",
"qty": "5"
}]
}, {
"id": 2,
"name": "Miscellaneous Property",
"choices": [
{
"id": 1,
"req_goods": "Office Rent",
"qty": "1"
}]
}];
function removeChoice(json, parentId, choiceId) {
for (var i = 0; i < json.length; i++) {
if (json[i].id === parentId) {
for (var j = 0; j < json[i].choices.length; j++) {
if (json[i].choices[j].id === choiceId) {
json[i].choices.splice(j, 1);
break;
}
}
break;
}
}
}
removeChoice(json, 1, 1);
console.log(json);
In both of the above methods I've passed the source you want to modify as a parameter to the removeChoice function whereas you can also directly use a variable available within the scope of execution of the removeChoice function and pass only parentId and choiceId as parameters in the below code snippet, you can replace items with the object on your controller's $scope.If you prefer isolation of the code you can pass the items object as a parameter to the removeChoice function as it won't be dependent on the external components directly being used in the method body, I would suggest to have separation of concerns.
var items = [
{
"id": 1,
"name": "Furniture & Fixture",
"choices": [
{
"id": 1,
"req_goods": "table",
"qty": "10"
},
{
"id": 2,
"req_goods": "chair",
"qty": "5"
}]
}, {
"id": 2,
"name": "Miscellaneous Property",
"choices": [
{
"id": 1,
"req_goods": "Office Rent",
"qty": "1"
}]
}];
function removeChoice(parentId, choiceId) {
for (var i = 0; i < items.length; i++) {
if (items[i].id === parentId) {
for (var j = 0; j < items[i].choices.length; j++) {
if (items[i].choices[j].id === choiceId) {
items[i].choices.splice(j, 1);
break;
}
}
break;
}
}
}
removeChoice(1, 1);
console.log(items);
Try This
$scope.removeChoice = function(parent_id,id) {
var TempArr=[];
var parentLength=$scope.choices[parent_id].length;
for(i=0;i<parentLength;i++ ){
if(parentLength[i]!==id){
TempArr.push(parentLength[i]);
}
if(i==parentLength-1){
$scope.choices[parent_id]=[];
$scope.choices[parent_id]=TempArr;
}
}
};

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

Resources