I'm currently trying to generate a table that can not only display values as dynamic as possible, but also have functionality that gets passed to a certain column. The draft of the structure is like this:
<Table
dataHeaders={[
{ headerTitle: 'ID', headerKey: 'id', filterable: true },
{ headerTitle: 'First Name', headerKey: 'firstname', filterable: true, sortable: true },
{ headerTitle: 'Last Name', headerKey: 'lastname', filterable: true, sortable: true },
{
headerTitle: 'Details',
text: 'Show details',
functionalColumn: true,
function: row => {
alert(`${row.id}: ${row.firstname} ${row.middlename} ${row.lastname}`);
},
},
{
headerTitle: 'Delete',
text: 'Delete',
functionalColumn: true,
function: row => {
const remainingData = this.state.data.filter(item => item.id !== row.id);
this.setState({ data: remainingData });
},
},
]}
data={[
{ id: 1, firstname: 'Jess', lastname: 'Smith' },
{ id: 2, firstname: 'Alex', lastname: 'Williams' },
{ id: 3, firstname: 'Tayler', lastname: 'Brown' },
{ id: 4, firstname: 'Hannah', lastname: 'Anderson' },
{ id: 5, firstname: 'Anna', lastname: 'Adams' },
{ id: 6, firstname: 'Michael', lastname: 'Johnson' },
{ id: 7, firstname: 'John', lastname: 'Willis' },
{ id: 8, firstname: 'Joey', lastname: 'Sullivan' },
{ id: 9, firstname: 'Chandler', lastname: 'Anderson' },
{ id: 10, firstname: 'Monica', lastname: 'Black' },
{ id: 11, firstname: 'Rachel', lastname: 'Tyson' },
{ id: 12, firstname: 'Alex', lastname: 'Doe' },
]}
/>
Showing the details works completely fine, using this code in the Table component:
<td key={`${metaColumn.text}-${index}`}>
<span className={'Table__delete'} onClick={metaColumn.function.bind(this, row)}>
{metaColumn.text}
</span>
</td>
However, and not surprisingly, manipulating the state of Table doesn't work properly, as apparently binding the method with bind(this, row) isn't sufficient.
Is there a way I can make this.state accessible in this kind of environment?
So, I finally figured out, why it wouldn't work. The reason is quite simple: you cannot change the context of this in arrow functions.
So instead of
function: row => {
const remainingData = this.state.data.filter(item => item.id !== row.id);
this.setState({ data: remainingData });
}
I used:
function(row) {
const remainingData = this.state.data.filter(item => item.id !== row.id);
this.setState({ data: remainingData });
}
Related
I'm trying to find an element on a multidimentionnal array usin JAVASCRIPT function, but I get error
This is my array's data:
export const datas = [
{
id: 1,
firstName: 'John',
tables: [
{ ID: 11, title: 'Lorem' },
{ ID: 12, title: 'Ipsum' },
],
},
{
id: 2,
firstName: 'Doe',
tables: [
{
ID: 22,
title: 'Arke',
nodes: [{ name: 'Name1' }, { name: 'Name2' }, { name: 'Name3' }],
},
{ ID: 23, title: 'Korem' },
],
},
{
id: 3,
firstName: 'Brad',
tables: [
{
ID: 30,
title: 'Mern',
nodes: [{ name: 'Name4' }, { name: 'Name5' }, { name: 'Name6' }],
},
{
ID: 31,
title: 'Full',
nodes: [{ name: 'Name7' }, { name: 'Name8' }, { name: 'Name9' }],
},
],
},
];
I've tried a reccursive function but it's not work, this is my code :
export const findById = (arr, id) => {
for (let o of arr) {
if (o.tables.length > 0) {
let a = findById(o.tables.nodes, 'id');
console.log(a);
}
}
};
I want to print the Object with ID 22, the problem is that I don't have the same structure in each dimension, and it still confuse me..
My Input : 22
My output :
{
ID: 22,
title: 'Arke',
nodes: [{ name: 'Name1' }, { name: 'Name2' }, { name: 'Name3' }],
},
Have you an idea how to edit my function to get my input's response ?
Your recursive function wasn't too far off, you need to check if the item as a tables first before recursively calling it again. And then finally just check the ID in the loop.
eg..
const datas=[{id:1,firstName:"John",tables:[{ID:11,title:"Lorem"},{ID:12,title:"Ipsum"}]},{id:2,firstName:"Doe",tables:[{ID:22,title:"Arke",nodes:[{name:"Name1"},{name:"Name2"},{name:"Name3"}]},{ID:23,title:"Korem"}]},{id:3,firstName:"Brad",tables:[{ID:30,title:"Mern",nodes:[{name:"Name4"},{name:"Name5"},{name:"Name6"}]},{ID:31,title:"Full",nodes:[{name:"Name7"},{name:"Name8"},{name:"Name9"}]}]}];
function findById(arr, ID) {
for (const a of arr) {
if (a.tables) {
const r = findById(a.tables, ID);
if (r) return r;
}
if (a.ID === ID) return a;
}
}
console.log(findById(datas, 22));
if you just need the nested data you can use flatMap and find
const findById = (arr, id) =>
arr
.flatMap(d => d.tables)
.find(t => t.ID === id)
const datas = [{
id: 1,
firstName: 'John',
tables: [{
ID: 11,
title: 'Lorem'
},
{
ID: 12,
title: 'Ipsum'
},
],
},
{
id: 2,
firstName: 'Doe',
tables: [{
ID: 22,
title: 'Arke',
nodes: [{
name: 'Name1'
}, {
name: 'Name2'
}, {
name: 'Name3'
}],
},
{
ID: 23,
title: 'Korem'
},
],
},
{
id: 3,
firstName: 'Brad',
tables: [{
ID: 30,
title: 'Mern',
nodes: [{
name: 'Name4'
}, {
name: 'Name5'
}, {
name: 'Name6'
}],
},
{
ID: 31,
title: 'Full',
nodes: [{
name: 'Name7'
}, {
name: 'Name8'
}, {
name: 'Name9'
}],
},
],
},
];
console.log(findById(datas, 22))
js has amazing array options https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
the ones which will help you most are probably:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flatMap
here are some examples
// get the base with id 22
const baseWith22ID = datas.filter(f => f.tables.filter(s => s.id = 22))
// (i guess you want this one) get all elements with id 22
const onlyElementsWith22ID = datas.flatMap(f => f.tables.filter(s => s.id = 22))
I have this object that I need to filter it.
let data = JSON.parse(this.getDataFromArray).map((x: any) => x.isEnabled === true);
I need to get in "data" only ID's of values that "isEnabled" is true.
Use Array.prototype.flatMap to achieve the result.
const dataArray = [
{ id: 1, name: "Alice", isEnabled: false },
{ id: 2, name: "Bob", isEnabled: true },
{ id: 3, name: "Charlie", isEnabled: true },
{ id: 4, name: "Dave", isEnabled: true },
{ id: 5, name: "Eve", isEnabled: false },
{ id: 6, name: "Frank", isEnabled: false },
];
let data = dataArray.flatMap(elm => elm.isEnabled ? [elm.id]: []);
console.log(data);
Please note that flatMap cannot be used in IE without a polyfill.
If you need IE support, use Array.prototype.forEach
const dataArray = [
{ id: 1, name: "Alice", isEnabled: false },
{ id: 2, name: "Bob", isEnabled: true },
{ id: 3, name: "Charlie", isEnabled: true },
{ id: 4, name: "Dave", isEnabled: true },
{ id: 5, name: "Eve", isEnabled: false },
{ id: 6, name: "Frank", isEnabled: false },
];
let data = [];
dataArray.forEach((elm) => {
if (elm.isEnabled) {
data.push(elm.id);
}
});
console.log(data);
Try this to filter first, and map to desired property:
JSON.parse(this.getDataFromArray).filter((x: any) => x.isEnabled === true).map((result: any) => result.id);
I would like to know how to get the object array list based on values matching in javascript
If any of object value matches with parameter, then return that array in javascript.
var objarr = [
{id:1, email: 'xyz#gmail.com', value: 10, name: 'ram'},
{id:2, email: 'xyz#gmail.com', value: 20, name: 'Tom'},
{id:3, email: 'ss#gmail.com', value: 30, name: 'Lucas'},
{id:4, email: 'ct#gmail.com', value: 40, name: 'Chris'},
{id:5, email: 'tam#gmail.com', value: 30, name: 'Lucas Tim'}
]
function getList(val){
var result=[];
var checkdata = objarr.filter(e=>{
if(Object.values(e)===val){
result.push(e);
}
return result;
})
}
console.log(result);
Expected Output:
getList('xyz#gmail.com');
scenario 1:
[
{id:1, email: 'xyz#gmail.com', value: 10, name: 'ram'},
{id:2, email: 'xyz#gmail.com', value: 20, name: 'Tom'}
]
scenario 2:
getList('Chris');
[
{id:4, email: 'ct#gmail.com', value: 40, name: 'Chris'}
]
Your Array.filter function should return either true or false depending on the search criteria.
Object.values returns an Array as output. To check whether a value is in an array, you can use Array.includes.
You should chck for value with Object.values(e).includes(val)
Working Fiddle
var objarr = [
{ id: 1, email: 'xyz#gmail.com', value: 10, name: 'ram' },
{ id: 2, email: 'xyz#gmail.com', value: 20, name: 'Tom' },
{ id: 3, email: 'ss#gmail.com', value: 30, name: 'Lucas' },
{ id: 4, email: 'ct#gmail.com', value: 40, name: 'Chris' },
{ id: 5, email: 'tam#gmail.com', value: 30, name: 'Lucas Tim' }
]
function getList(val) {
var checkdata = objarr.filter(e => {
if (Object.values(e).includes(val)) {
return true;
}
return false;
})
return checkdata;
}
console.log(getList('xyz#gmail.com'));
console.log(getList('Chris'));
Simplified version
var objarr = [
{ id: 1, email: 'xyz#gmail.com', value: 10, name: 'ram' },
{ id: 2, email: 'xyz#gmail.com', value: 20, name: 'Tom' },
{ id: 3, email: 'ss#gmail.com', value: 30, name: 'Lucas' },
{ id: 4, email: 'ct#gmail.com', value: 40, name: 'Chris' },
{ id: 5, email: 'tam#gmail.com', value: 30, name: 'Lucas Tim' }
]
const getList = (val) => objarr.filter(e => Object.values(e).includes(val))
console.log(getList('xyz#gmail.com'));
console.log(getList('Chris'));
You can make use of filter and using Object.values to get all the values of an object and then use some to get the desired result.
ONE LINER
objarr.filter((o) => Object.values(o).some((v) => v === val));
var objarr = [
{ id: 1, email: "xyz#gmail.com", value: 10, name: "ram" },
{ id: 2, email: "xyz#gmail.com", value: 20, name: "Tom" },
{ id: 3, email: "ss#gmail.com", value: 30, name: "Lucas" },
{ id: 4, email: "ct#gmail.com", value: 40, name: "Chris" },
{ id: 5, email: "tam#gmail.com", value: 30, name: "Lucas Tim" },
];
const getList = val => objarr.filter((o) => Object.values(o).some(v => v === val));
console.log(getList("xyz#gmail.com"));
console.log(getList("Chris"));
/* This is not a part of answer. It is just to give the output full height. So IGNORE IT */
.as-console-wrapper { max-height: 100% !important; top: 0; }
I have an array of objects displayed on the UI. Now I want to change the style of the data which doesn't match with the data from another array of objects.
Basically my goal is to create a boolean data which checks if the data are matching for both array of objects, and according to this boolean data the style will be changed.
Here is what I have.
And codesandbox link
import React from "react";
import "./styles.css";
const result1 = [
{ id: 1, name: "Sandra", type: "user", username: "sandra" },
{ id: 2, name: "John", type: "admin", username: "johnny2" },
{ id: 3, name: "Peter", type: "user", username: "pete" },
{ id: 4, name: "Bobby", type: "user", username: "be_bob" },
{ id: 5, name: "Bob", type: "user", username: "bob" },
{ id: 6, name: "James", type: "user", username: "james" },
{ id: 7, name: "Bill", type: "user", username: "bill" }
];
const result2 = [
{ id: 2, name: "John", username: "johnny2" },
{ id: 5, name: "Bob", type: "user", username: "bob" },
{ id: 4, name: "Bobby", username: "be_bob" }
];
export default function App() {
const excludedPerson = result1.filter(
(person1) => !result2.some((person2) => person1.name === person2.name)
);
console.log(excludedPerson);
return (
<div className="App">
{result1.map((person) => (
<ul key={person.id}>
<div>{person.name}</div>
<div
style={{
textDecoration: "boolean" ? "line-through" : "none" // instead of string it should be a boolean
}}
>
{person.username}
</div>
</ul>
))}
</div>
);
}
Instead of using filter you can use map and get the boolean excludedPerson array
changes:
1) use map instead of filter
const excludedPerson = result1.map(
(person1) => !result2.some((person2) => person1.name === person2.name)
);
2) Add second parameter in JSX i.e index
{result1.map((person, i) => (
3) change CSS styles accordingly: I've strike through the result1 elements that are not in result2
textDecoration: !excludedPerson[i] ? "line-through" : "none"
CODE DEMO
import React from "react";
import "./styles.css";
const result1 = [
{ id: 1, name: "Sandra", type: "user", username: "sandra" },
{ id: 2, name: "John", type: "admin", username: "johnny2" },
{ id: 3, name: "Peter", type: "user", username: "pete" },
{ id: 4, name: "Bobby", type: "user", username: "be_bob" },
{ id: 5, name: "Bob", type: "user", username: "bob" },
{ id: 6, name: "James", type: "user", username: "james" },
{ id: 7, name: "Bill", type: "user", username: "bill" }
];
const result2 = [
{ id: 2, name: "John", username: "johnny2" },
{ id: 5, name: "Bob", type: "user", username: "bob" },
{ id: 4, name: "Bobby", username: "be_bob" }
];
export default function App() {
const excludedPerson = result1.map(
(person1) => !result2.some((person2) => person1.name === person2.name)
);
console.log(excludedPerson);
return (
<div className="App">
{result1.map((person, i) => (
<ul key={person.id}>
<div>{person.name}</div>
<div
style={{
textDecoration: !excludedPerson[i] ? "line-through" : "none" // instead of string it should be a boolean
}}
>
{person.username}
</div>
</ul>
))}
</div>
);
}
Mabye something like this? Return only the common objects in the two array of objects
const result1 = [
{ id: 1, name: 'Sandra', type: 'user', username: 'sandra' },
{ id: 2, name: 'John', type: 'admin', username: 'johnny2' },
{ id: 3, name: 'Peter', type: 'user', username: 'pete' },
{ id: 5, name: 'Bob', type: 'user', username: 'bob' },
{ id: 6, name: 'James', type: 'user', username: 'james' },
{ id: 7, name: 'Bill', type: 'user', username: 'bill' },
];
const result2 = [
{ id: 2, name: 'John', username: 'johnny2' },
{ id: 5, name: 'Bob', type: 'user', username: 'bob' },
{ id: 4, name: 'Bobby', username: 'be_bob' },
];
const output = result1.filter(({ id: id1 }) =>
result2.some(({ id: id2 }) => id2 === id1)
);
console.log(output);
I have an array which have many records. Need to merge objects based on a condition(not applicable to all the object available inside an array), In this case first need to compare the data with name.
step 1: Need to find objects in array which have similar name.
step 2: If we have same data, next compare the status key among the matched data.
step 3:
case1: If any one of the object among the matched data has status as true(set status: true) then need to merge all the likings key to that object.
case2: If all the object among the matched data has status as false then(set status: false) need to merge all the likings key to any of the object.
How to achieve this?
Array
[
{
name: 'jane',
age: 10,
status: true,
likings: [{ sports: 'football', books: 'harrypotter' }],
},
{
name: 'sam',
age: 20,
status: false,
likings: [{ sports: 'basketball', books: 'book1' }],
},
{
name: 'jane',
age: 10,
status: false,
likings: [{ sports: 'chess', books: 'book2' }],
},
{
name: 'robert',
age: 40,
status: false,
likings: [{ sports: 'carrom', books: 'book3' }],
},
{
name: 'jane',
age: 10,
status: false,
likings: [{ sports: 'gaming', books: 'book4' }],
},
];
Expected o/p
[
{
name: 'jane',
age: 10,
status: true,
likings: [
{ sports: 'football', books: 'harrypotter' },
{ sports: 'gaming', books: 'book4' },
{ sports: 'chess', books: 'book2' },
],
},
{
name: 'sam',
age: 20,
status: false,
likings: [{ sports: 'basketball', books: 'book1' }],
},
{
name: 'robert',
age: 40,
status: false,
likings: [{ sports: 'carrom', books: 'book3' }],
},
];
You can use .reduce() to merge all objects with the same name into a Map. This can by keeping a map of keys of name, and values of objects with that name. Whenever you encounter a new object in your array, you can check if it exists in the map. If it does, you can add to the likings array stored in the associated object. You can also update the status to true if the current object is true. If the object's name doesn't exist in the map as a key, you can add the object as a value, which further subsequent iterations of reduce can merge into.
See example below:
const arr = [ { name: 'jane', age: 10, status: true, likings: [{ sports: 'football', books: 'harrypotter' }], }, { name: 'sam', age: 20, status: false, likings: [{ sports: 'basketball', books: 'book1' }], }, { name: 'jane', age: 10, status: false, likings: [{ sports: 'chess', books: 'book2' }], }, { name: 'robert', age: 40, status: false, likings: [{ sports: 'carrom', books: 'book3' }], }, { name: 'jane', age: 10, status: false, likings: [{ sports: 'gaming', books: 'book4' }], }, { name: 'sam', age: 10, status: false, likings: [{ sports: 'gaming', books: 'book5' }], }];
const merged = [...arr.reduce((m, o) => {
const curr = m.get(o.name) || {};
return m.set(o.name, {...o, status: curr.status || o.status, likings: [...(curr && curr.likings || []), ...o.likings]});
}, new Map).values()]
console.log(merged);
I don't think I fully understood your requirement especially about "similar name". So I assume that you want to group the records based on the "name" and all the records which have the same "name" will have the same "age".
The solution below is grouping the records using an object hash and keep concatenating the likings into the element. After finishing it, return the all elements of the object by calling Object.values() which should maintain the order of appearance of names.
Is this something you want, or at least give you some idea? Hope it helps.
function merge(records) {
const hash = {};
for (let i = 0; i < records.length; i++) {
const element = records[i];
const key = element.name; // if you want to do something for "similarity", do something here.
hash[key] = {
...element,
status: (hash[key] && hash[key].status) || element.status,
likings: element.likings.concat((hash[key] && hash[key].likings) || []),
};
}
return Object.values(hash);
}
const data = [
{
name: "jane",
age: 10,
status: true,
likings: [{ sports: "football", books: "harrypotter" }],
},
{
name: "sam",
age: 20,
status: false,
likings: [{ sports: "basketball", books: "book1" }],
},
{
name: "jane",
age: 10,
status: false,
likings: [{ sports: "chess", books: "book2" }],
},
{
name: "robert",
age: 40,
status: false,
likings: [{ sports: "carrom", books: "book3" }],
},
{
name: "jane",
age: 10,
status: false,
likings: [{ sports: "gaming", books: "book4" }],
},
];
console.log(merge(data));