Angular2: loop through a recently pushed array and push from another - arrays

I have an array object
MainArray = {"Data":
[{"Group": "GroupA"},{"Group": "GroupB"}]
}
then I loop through the array and created a new
let _newArray : any[] = [];
MainArray.Data.forEach(item => {
_newArray.push({
groupname : item.Group,
columns: ["column1","column2","column3"]
});
//loop through _newArray.columns
});
then I need to loop through the columns of new Array inside the Main Array loop
and push an array from another..
SecondArray = [{group: "GroupA", value: "firstfield", count: 14 },{group: "GroupA", field: "secondfield", count:23 },{group: "GroupB", field: "randomfield", count:1 }]
so the output should be
_newArray = [{
groupname: "GroupA",
columns: ["column1","column2","column3"]
col1: [{"firstfield":14, "secondfield": 23 }]
col2: "",
col3: ""
},{GroupB...}]
what I tried:
Object.keys( _newArray[0].columns).forEach( function(value, key) {
console.log(this._SecondArray[item.Group])
// push 'col + index: [Second Array]'
});

In your SecondArray the first object is having a 'value' key. I assumed it as "field"
let MainArray = {
"Data":
[{ "Group": "GroupA" }, { "Group": "GroupB" }]
}
// First push
let _newArray = [];
MainArray.Data.forEach(item => {
_newArray.push({
'groupname': item.Group,
'columns': ["column1", "column2", "column3"]
})
})
let SecondArray = [{ group: "GroupA", field: "firstfield", count: 14 }, { group: "GroupA", field: "secondfield", count: 23 }, { group: "GroupB", field: "randomfield", count: 1 }];
// Second push
_newArray.forEach(item => {
console.log(item)
let i = 1;
item.columns.forEach(cols => {
console.log(cols)
if (i == 1) {
item["col" + i] = {}
SecondArray.forEach(subItem => {
console.log(subItem)
if (subItem.group == item.groupname) {
item["col" + i][subItem.field] = subItem.count
}
})
i++
} else {
item["col" + i++] = ""
}
})
})
console.log(_newArray);

Related

REACT: Updating nested state

I have two sets of data. Both are saved in a states.I want to update the rowsData inside the data1 state based on the values in data2 state. The "row" value in the data2 object refers to the "id" of rowsData in the data1 state and columns in the data2 refers to any data beside id in the rowsData object in data1. I want to pick "row" and "column" from data2 and cahnge the respective data inside rowsData in data1.
let tableData = {
columnsDef: [
{ title: "id",field: "id",className: "header-style" },
{ title: "First_name", field: "First_name", className: "header-style" },
{ title: "Last_name", field: "Last_name", className: "header-style" },
{ title: "Email", field: "Email", className: "header-style" },
],
rowsData:[
{ id: "1", First_name: "Donald", Last_name: "OConnell", Email: "DOCONNEL" },
{ id: "2", First_name: "Douglas", Last_name: "Grant", Email: "DGRANT" },
{ id: "3", First_name: "Jennifer", Last_name: "Whalen", Email: "JWHALEN" },
{ id: "4", First_name: "Michael", Last_name: "Hartstein", Email: "MHARTSTE" },
{ id: "5", First_name: "Pat", Last_name: "Fay", Email: "PFAY" },
{ id: "6", First_name: "Susan", Last_name: "Mavris", Email: "SMAVRIS" },
{ id: "7", First_name: "Hermann", Last_name: "Baer", Email: "HBAER" }
],
file: [
{ file: { path: "dummy_data_3 .csv"}}
],
}
let updatedTableData = [
{ "row": 2, "column": "Email", "oldValue": "DGRANT", "newValue": "DGRANT UPDATED" },
{ "row": 6, "column": "First_name", "oldValue": "Susan", "newValue": "SUSAN UPDATED" },
{ "row": 4, "column": "Last_name", "oldValue": "Hartstein", "newValue": "Hartstein UPDATED" }
]
const [data1, setData1] = useState(tableData)
const [data2, setData2] = useState(updatedTableData)
Here is the codesandbox link for the issue.
https://codesandbox.io/s/reverent-firefly-r87huj?file=/src/App.js
You can follow these steps for updating data1 from handleAppyChanges function:
Create a copy of rowsData:
const td = [...data1.rowsData];
Iterate over data2 and find related item, then update its related column:
data2.forEach((item) => {
let row = data1.rowsData.find((r) => r.id === item.row);
if (row) {
let index = data1.rowsData.findIndex((v) => v === row);
row[item.column] = item.newValue;
td[index] = row;
}
});
Update table data via state:
const newData = {
file: data1.file,
rowsData: td,
columnDef: data1.columnsDef
};
setData1(newData);
Here's the full function:
const handleAppyChanges = () => {
const td = [...data1.rowsData];
data2.forEach((item) => {
let row = data1.rowsData.find((r) => r.id === item.row);
if (row) {
let index = data1.rowsData.findIndex((v) => v === row);
row[item.column] = item.newValue;
td[index] = row;
}
});
const newData = {
file: data1.file,
rowsData: td,
columnDef: data1.columnsDef
};
setData1(newData);
console.log("Updated Data 1: ", td);
};
You can access the full code via codesandbox:
Apply into onChange and check it.
const handleAppyChanges = () => {
data2.map((item) => {
data1.rowsData.map((data) => {
//match both id and row
if (data.id == item.row) {
//check column is there or not
let column = data.hasOwnProperty(item.column);
if (column) {
//if yes then change the value
data[item.column] = item.newValue;
}
}
});
});
setData1({ ...data1 });
};

How can I change TS object array format?

Array which I want change
I have got this array in TypeScript, I want it change as bellow.
list = [{id : 1, name : bus, active : 1}, {id : 2, name : car}]
Can anyone help me?
You can map the input and reduce each element to an object.
const list = [
[{ id: 1 }, { name: 'bus' }, { active: 1 }],
[{ id: 2 }, { name: 'car' }],
];
const result = list.map((el) => {
return el.reduce((acc, curr) => {
return { ...acc, ...curr };
}, {});
});
console.log(result);

Array to array of objects

I have an array of country such as:
country=["Afganistan","Albania","Algeria"]
How can I convert this array into array of objects such as:
newarray=[
{ key: 'Afghanistan', value: 'Afghanistan', text: 'Afghanistan' },
{ key: 'Albania', value: 'Albania', text: 'Albania' },
{ key: 'Algeria', value: 'Algeria', text: 'Algeria' }
]
country=["Afganistan","Albania","Algeria"]
let newarray = [];
country.forEach(item => {
newarray.push({
key: item,
value: item,
text: item
});
});
console.log(newarray);
I found the answer. The method will be:-
let newarray = [];
country.map(item => {
return newarray.push({ key: item, value: item, text: item })
})

How to loop through object for finding a particular value using typescript and react?

I want to hide a button if there is atleast one order or subareas that at least one orders whose status 'ACCEPTED' or 'DONE'.
How can I hide the "Hide me" Menu item when either item has at least one area with order status 'ACCEPTED' OR 'DONE' or at least one area with subareas order with status 'ACCEPTED' or 'DONE'.
Below is the react code with the item I am trying to process
function Parent() {
const item = {
owner: {
id: '1',
cognitoId: '2',
},
areas: [{
id: '1',
orders: [
{
id: '1',
status: 'ASSIGNED',
}, {
id: '2',
status: 'ACCEPTED',
}
],
subAreas: [
{
id: '1',
orders: [
{
id: '4',
status: 'DONE',
}
],
}
]
}, {
id: '2',
orders: [{
id: '3',
status: 'ASSIGNED',
}, {
id: '4',
status: 'ACCEPTED',
}
],
subAreas: [{
id: '2',
orders: [{
id: '5',
status: 'DONE',
}, {
id: '6',
status: 'ACCEPTED',
}
],
}
]
}
]
}
return ({
item && item.owner && item.owner.cognitoId && (
< Menu > Hide me < / Menu > )
});
}
this Item is reference to how the data will look.
For additional information...Item is of type Item which is like below
export interface Item {
id: string;
name: string;
areas?: Area[];
}
export interface Area {
id: string;
Orders?: Order[];
subAreas?: Area[];
}
export interface Order {
id: string;
status: OrderStatus; //this is the one we are looping through
}
export interface OrderStatus {
NEW = 'NEW',
ASSIGNED = 'ASSIGNED',
SENT = 'SENT',
ACCEPTED = 'ACCEPTED',
REJECTED = 'REJECTED',
DONE = 'DONE',
}
what i have tried is like below
const hasDoneAccepted = () => {
return Object
.keys(item)
.some(key =>
(key === 'status' &&
['DONE', 'ACCEPTED'].indexOf(item[key]) > -1) ||
(typeof item[key] === 'object' &&
hasDoneAccepted(item[key])));
}
But this gives me an error like below,
Element implicitly has any type because expression of type "status" cant be used on index type 'Item'. property status doesnt exist on type 'Item'.
i am new to using typescript and not sure whats going wrong. could someone help me with this. thanks.
EDIT:
using the solution provided
const hasAcceptedOrDoneOrders =
item.areas?.reduce<Order[]>((acc, area) => { //error here
area.orders?.forEach(order => acc.push(order));
area.subAreas?.forEach(subArea => subArea.orders?.forEach(order =>
acc.push(order)));
return acc;
}, [])
.some(order => order.status === "ACCEPTED" || order.status === "DONE");
}
this gives me an here at line
item.areas?.reduce<Order[]>((acc, area) =>
"parsing error: expression expected"
looping through the object is always an option. I'd use a helper method too. Something like this:
hideBool = false;
for(cost area of item.areas()) {
if(hideBool) { break; }
hideBool = this.checkArray(area.orders);
if(!hideBool) {
for(const subArea of area.subAreas) {
hideBool = this.checkArray(subArea);
if(hideBool) { break; }
}
}
}
checkArray(array: any[]) {
for( const item in array) {
if(item.status === 'ACCEPTED' || item.status === 'DONE') {
return true;
}
}
return false;
}
This is how you can write the filter function:
const hasAcceptedOrDoneOrders =
item.areas?.reduce<Order[]>((acc, area) => {
area.orders?.forEach(order => acc.push(order));
area.subAreas?.forEach(subArea => subArea.orders?.forEach(order => acc.push(order)));
return acc;
}, [])
.some(order => order.status === "ACCEPTED" || order.status === "DONE");
and use it to conditional display React element:
return !hasAcceptedOrDoneOrders && <Menu>Hide me</Menu>;
However, to eliminate all the TypeScript syntax errors you need to correctly type the item object and fix the data schema:
const item: Item = {
id: "1",
name: "Item1",
owner: { id: "1", cognitoId: "2" },
areas: [
{
id: "1",
orders: [
{ id: "1", status: OrderStatus.ASSIGNED },
{ id: "2", status: OrderStatus.ACCEPTED }
],
subAreas: [
{
id: "1",
orders: [{ id: "4", status: OrderStatus.DONE }]
}
]
},
{
id: "2",
orders: [
{ id: "3", status: OrderStatus.ASSIGNED },
{ id: "4", status: OrderStatus.ACCEPTED }
],
subAreas: undefined
}
]
};
Schema:
interface Item {
id: string;
name: string;
areas?: Area[];
owner: any;
}
enum OrderStatus {
NEW = 'NEW',
ASSIGNED = 'ASSIGNED',
SENT = 'SENT',
ACCEPTED = 'ACCEPTED',
REJECTED = 'REJECTED',
DONE = 'DONE',
}

How to remove items in one array if other has it?

How to remove item from array B if array A has it. I want to iterate through by ID.
array A: it has all the items
[{
"Name":"John",
"Id":1
},
{
"Name":"Peter",
"Id":2
},
{
"Name":"Phillip",
"Id":3
},
{
"Name":"Abby",
"Id":4
},
{
"Name":"Don",
"Id":5
}]
array B: has just the selected items
[{
"Name":"John",
"Id":1
},
{
"Name":"Abby",
"Id":4
}]
I want to remove from array A John and Abby by Id, because they are in array b.
for (var i = 0; i < a.length; i++) {
if (b[i].Id == ta[i].Id) {
for (var j = 0; j < b[j]; j++) {
a.splice(i, 1);
}
}
}
this is not working as I thought
You could first get all id's of person objects in b:
let idsInB: number[] = b.map(person => person.Id); // > [1, 4]
This array of id's can be used to filter a, and then assign the result back to a. Let's contain that in a function cleanA:
function cleanA(): void {
let idsInB: number[] = b.map(person => person.Id);
a = a.filter((person) => -1 === idsInB.indexOf(person.Id));
}
All you need to do now is call cleanA whenever the contents of b changes.
Full working example:
interface Person {
Id: number;
Name: string;
}
let a: Person[] = [
{ Id: 1, Name: "John" },
{ Id: 2, Name: "Peter" },
{ Id: 3, Name: "Phillip" },
{ Id: 4, Name: "Abby" },
{ Id: 5, Name: "Don" },
];
let b: Person[] = [
{ Id: 1, Name: "John" },
{ Id: 4, Name: "Abby" },
];
function cleanA(): void {
let idsInB: number[] = b.map(person => person.Id);
a = a.filter((person) => -1 === idsInB.indexOf(person.Id));
}
presentArray(a, 'A before clean');
cleanA();
presentArray(a, 'A after clean');
// -------------------------------------------------------
// Displaying purposes only:
// -------------------------------------------------------
function presentArray(arr, msg) {
document.body.innerHTML += `<br><b>${msg}:</b><br>[<br>`
+ arr.map(person => ` { Id: ${person.Id}, Name: ${person.Name} },<br>`)
.join('')
+ ' ]<br><br>';
}

Resources