Adding key value pair to specific objects in an array - arrays

I have an array of objects that looks like this:
[{headerName: "Test 1", field: "Test 1", type_id: 1}, {headerName: "Test 2", field: "Test 2", type_id: 2}, {headerName: "Test 3", field: "Test 3", type_id: 3}, {headerName: "Name", field: "Name", type_id: 3}, {headerName: "Income", field: "Income", type_id: 2}]
This is just a basic example of what the array might look like as it can be of any length. Basically what I need to do is when the type_id is 3 I need to add an extra key/value pair to those objects in the array.
How would I go about doing this?
Any help would be much appreciated.
Thanks for your time.
UPDATE:
Key/value pair I am trying to add is : cellRenderer: customEditor

An es6 solution
yourArray = yourArray.map( obj => {
if( obj.type_id === 3 ){
return { ...obj, cellRenderer: customEditor };
}
return obj;
}
An es5 solution
yourArray = yourArray.map( function( obj ){
if( obj.type_id === 3 ){
Object.defineProperty(obj, "cellRenderer", { value : customEditor })
}
return obj;
}

The solution using Array.map and Object.keys functions:
var arr = [{headerName: "Test 1", field: "Test 1", type_id: 1}, {headerName: "Test 2", field: "Test 2", type_id: 2}, {headerName: "Test 3", field: "Test 3", type_id: 3}, {headerName: "Name", field: "Name", type_id: 3}, {headerName: "Income", field: "Income", type_id: 2}],
extraObj = {'cellRenderer': 'customEditor'};
arr.map(function(obj){
if (obj['type_id'] === 3) {
Object.keys(this).forEach((k) => obj[k] = this[k]);
}
}, extraObj);
console.log(JSON.stringify(arr, 0, 4));
The output:
[
{
"headerName": "Test 1",
"field": "Test 1",
"type_id": 1
},
{
"headerName": "Test 2",
"field": "Test 2",
"type_id": 2
},
{
"headerName": "Test 3",
"field": "Test 3",
"type_id": 3,
"cellRenderer": "customEditor"
},
{
"headerName": "Name",
"field": "Name",
"type_id": 3,
"cellRenderer": "customEditor"
},
{
"headerName": "Income",
"field": "Income",
"type_id": 2
}
]

Another take combining map and Object.assign
var data = [{headerName: "Test 1", field: "Test 1", type_id: 1}, {headerName: "Test 2", field: "Test 2", type_id: 2}, {headerName: "Test 3", field: "Test 3", type_id: 3}, {headerName: "Name", field: "Name", type_id: 3}, {headerName: "Income", field: "Income", type_id: 2}];
var extend = { cellRenderer: 'customEditor' }
data = data.map( item => {
if( item.type_id == 3 ){
return Object.assign( item, extend );
}
return item;
});

Related

How to get the selected values in a DataGrid with React Material UI

I'm working with a React MUI DataGrid. I need to get the values of the selected rows. At the moment, only the ids are coming through, and I get several errors throughout.
rows = data;
const columns = [
{
field: "id",
headerName: "ID",
sortable: false,
hide: true,
},
{
field: "firstName",
headerName: "First Name",
},
{
field: "lastName",
headerName: "Last Name",
},
{
field: "age",
headerName: "Age",
}
];
This is my React Hook.
const [ selection, setSelection ] = useState<GridSelectionModel>([]);
And this is the DataGrid.
<div style={{ height: 400, width: "100%" }}>
<DataGrid
rows={rows}
columns={columns}
checkboxSelection
getRowId={(row) => row.id}
onSelectionModelChange={(newSelection) => {
setSelection(newSelection);
console.log("selection", selection)
}}
{...rows}
/>
</div>
This prints the id.
<p>{selection.map((data) => data)}</p>
But, what I need, and I'm not able to figure out is:
{selection.map((data) => {
return (
<div key={data.id}>. <---ERROR
<p>{data.firstName}</p> <---ERROR
<p>{data.lastName}</p> <---ERROR
</div>
)
})}
When I do it this way, I get the following error: "Property does not exist on type 'GridRowId'."
selection will be an array of IDs instead of an array of items. You can remap the IDs back to your items, E.g,
data.json
[
{
"id": "id-001",
"firstName": "First Name 1",
"lastName": "Last Name 1",
"age": 1
},
{
"id": "id-002",
"firstName": "First Name 2",
"lastName": "Last Name 2",
"age": 2
},
{
"id": "id-003",
"firstName": "First Name 3",
"lastName": "Last Name 3",
"age": 3
},
{
"id": "id-004",
"firstName": "First Name 4",
"lastName": "Last Name 4",
"age": 4
},
{
"id": "id-005",
"firstName": "First Name 5",
"lastName": "Last Name 5",
"age": 5
}
]
App.tsx
import { useState } from "react";
import { DataGrid, GridSelectionModel } from "#mui/x-data-grid";
import data from "./data.json";
const columns = [
{
field: "id",
headerName: "ID",
sortable: false,
hide: true
},
{
field: "firstName",
headerName: "First Name"
},
{
field: "lastName",
headerName: "Last Name"
},
{
field: "age",
headerName: "Age"
}
];
// NOTE: Pulls in imported json data.
const rows = data;
export default function App() {
const [selection, setSelection] = useState<GridSelectionModel>([]);
return (
<div>
<div style={{ height: 400, width: "100%" }}>
<DataGrid
rows={rows}
columns={columns}
checkboxSelection
gridRowId={(row) => row.id}
onSelectionModelChange={setSelection}
{...rows}
/>
</div>
<div>
{selection
.map((selectedId) => data.find((item) => item.id === selectedId))
.map(({ id, firstName, lastName }) => (
<div key={id}>
<p>{firstName}</p>
<p>{lastName}</p>
</div>
))}
</div>
</div>
);
}
For those using TypeScript, adding the following allowed the accepted code above to work.
Added "GridColDef[]" type.
const columns: GridColDef[] = [
{
field: "id",
headerName: "ID",
sortable: false,
hide: true
},
{
field: "firstName",
headerName: "First Name"
},
{
field: "lastName",
headerName: "Last Name"
},
{
field: "age",
headerName: "Age"
}
];
And adding a type of "any" where I'm pulling in the data.
const rows: any = data;

Filter Array of Object from another Array of Object

Currently I'm filtering data based from questions that have checked property value equals to true..
const data = [
{Name: "foo", X1: "1", X2: "1", Other: "Test1"},
{Name: "bar", X1: "2",X2: "2",Other: "Test2"},
{Name: "test",X1: "2",X2: "3",Other: "Test3"}
];
const questions = [{rows: {text: "Text 1", checked: true,fields: "1",column: "X1"}
}, {rows: {text: "Text 2", checked: true,fields: "2",column: "X1"}
}, {rows: {text: "Text 3", checked: false,fields: "1",column: "X2"}
}, {rows: {text: "Text 4", checked: false,fields: "2",column: "X2"}
}, {rows: {text: "Text 5", checked: false,fields: "3",column: "X2"}
}];
console.log(questionArr);
// console.log(dataArr);
const res = data.filter(d => questions.find(f => d[f.rows.column] === f.rows.fields && f.rows.checked));
which works but does not work when filtering the actual data below. I think there's a slight difference between the question object and the actual question object below.. What should be my filter code when accessing these kind of structure ?
I think this is what you're looking for. I matched the data structure to the image in your question. Let me know if I missed something.
const data = [
{ Name: "foo", X1: "1", X2: "1", Other: "Test1" },
{ Name: "bar", X1: "2", X2: "2", Other: "Test2" },
{ Name: "test", X1: "2", X2: "3", Other: "Test3" }
];
const questions = [
{ rows: [{ text: "Text 1", checked: true, fields: "2", column: "X1" }] },
{ rows: [{ text: "Text 2", checked: true, fields: "2", column: "X1" }] },
{ rows: [{ text: "Text 3", checked: false, fields: "1", column: "X2" }] },
{ rows: [{ text: "Text 4", checked: false, fields: "2", column: "X2" }] },
{ rows: [{ text: "Text 5", checked: false, fields: "3", column: "X2" }] }
];
const result = data.filter(function(item){
return questions.some(function(question){
return question.rows.some(function(row){
return (row.checked && item[row.column] === row.fields);
});
});
});
console.log(result);
The compact version
const result = data.filter((item) => questions.some((question) => question.rows.some((row) => (row.checked && item[row.column] === row.fields))));
With perf in mind
const data = [
{ Name: "foo", X1: "1", X2: "1", Other: "Test1" },
{ Name: "bar", X1: "2", X2: "2", Other: "Test2" },
{ Name: "test", X1: "2", X2: "3", Other: "Test3" }
];
const questions = [
{ rows: [{ text: "Text 1", checked: true, fields: "2", column: "X1" }] },
{ rows: [{ text: "Text 2", checked: true, fields: "2", column: "X1" }] },
{ rows: [{ text: "Text 3", checked: false, fields: "1", column: "X2" }] },
{ rows: [{ text: "Text 4", checked: false, fields: "2", column: "X2" }] },
{ rows: [{ text: "Text 5", checked: false, fields: "3", column: "X2" }] }
];
const result = {};
for(let a = 0, b = data.length; a < b; a++){
const item = data[a];
for(let c = 0, d = questions.length; c < d; c++){
const rows = questions[c].rows;
for(let e = 0, f = rows.length; e < f; e++){
const row = rows[e];
if(row.checked && item[row.column] === row.fields){
result[item.Name] = item;
break;
}
}
}
}
// this could be replaced with Object.values(result);
const matches = [];
for(let match in result){
matches.push(result[match]);
}
// not supported by IE yet
// Object.values(result);
console.log(matches);

Grouping objects with lodash or ES5

I'm a javascript noobie, I started to use the library lodash and I'm having some problems. Can someone help me? :/
Input:
var a = [{group: 'A', title: 'test1', value: 'test2'},
{group: 'A', title: 'test2', value: 'test3'},
{group: 'B', title: 'test3', value: 'test4'},
{group: 'B', title: 'test1', value: 'test2'},]
Output:
var a = {A: [
{ title: 'test1', value: 'test2'},
{ title: 'test2', value: 'test3'}
],
B: [
{ title: 'test1', value: 'test2'},
{ title: 'test2', value: 'test3'}
],}
You can group with _.groupBy() and then use _.mapValues() on each group to remove the group property from the objects by mapping them to a new object using _.omit().
const a = [{group: 'A', title: 'test1', value: 'test2'},
{group: 'A', title: 'test2', value: 'test3'},
{group: 'B', title: 'test3', value: 'test4'},
{group: 'B', title: 'test1', value: 'test2'}
];
const result = _(a)
.groupBy('group') // group by the group prop
.mapValues((group) => group.map((o) => _.omit(o, 'group'))) // remove the group prop from each item
.value();
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
The lodash documentation for group by is pretty explicit you can find it here.
In your case it would look something like this.
_.groupBy(a, 'group')
You can also do it yourself pretty easily as well using the reduce function. It would look something like this:
let groups = a.reduce((grouping, currentItem) => {
if (!grouping[currentItem.group]) {
grouping[currentItem.group] = []
}
grouping[currentItem.group].push(currentItem);
return grouping;
}, {});
A working example can be found here.
In both cases the result would be an object with the groups as property names.
{
"A": [{
"group": "A",
"title": "test1",
"value": "test2"
}, {
"group": "A",
"title": "test2",
"value": "test3"
}],
"B": [{
"group": "B",
"title": "test3",
"value": "test4"
}, {
"group": "B",
"title": "test1",
"value": "test2"
}]
}

Combining multiple json and displaying it in Angular UI Grid

i am trying to get json from multiple source and want to display it in the single Angular UI grid. in all these source first field is common .
Data format :
Source :1
var one=[
{ col1: "Heading 1", col2: "First 12", col3: "First 13"},
{ col1: "Heading 2", col2: "First 22", col3: "First 23"},
{ col1: "Heading 3", col2: "First 32", col3: "First 33"},
{ col1: "Heading 4", col2: "First 42", col3: "First 43"},
{ col1: "Heading 5", col2: "First 52", col3: "First 53"}
];
Source: 2
var two=[
{ col1: "Heading 1", col2: "Second 12", col3: "Second 13"},
{ col1: "Heading 2", col2: "Second 22", col3: "Second 23"},
{ col1: "Heading 3", col2: "Second 32", col3: "Second 33"},
{ col1: "Heading 4", col2: "Second 42", col3: "Second 43"},
{ col1: "Heading 5", col2: "Second 52", col3: "Second 53"}
];
I want it to be displayed in gird like this
Source:
var app = angular.module('plunker', ['ui.grid', 'ui.grid.selection']);
app.controller('MainCtrl', ['$scope', 'uiGridConstants', function($scope, uiGridConstants) {
var one=[
{ col1: "Heading 1", col2: "First 12", col3: "First 13"},
{ col1: "Heading 2", col2: "First 22", col3: "First 23"},
{ col1: "Heading 3", col2: "First 32", col3: "First 33"},
{ col1: "Heading 4", col2: "First 42", col3: "First 43"},
{ col1: "Heading 5", col2: "First 52", col3: "First 53"}
]; 1
1
var two=[
{ col1: "Heading 1", col2: "Second 12", col3: "Second 13"},
{ col1: "Heading 2", col2: "Second 22", col3: "Second 23"},
{ col1: "Heading 3", col2: "Second 32", col3: "Second 33"},
{ col1: "Heading 4", col2: "Second 42", col3: "Second 43"},
{ col1: "Heading 5", col2: "Second 52", col3: "Second 53"}
];
var finalObj = {
"firstData":one,
"secondData":two
}
console.log("finalObj"+JSON.stringify(finalObj));
$scope.gridOptions = {
columnDefs: [
{field: 'firstData.col1', displayName: 'Column 1', width: 175},
{field: 'firstData.col2', displayName: 'Column 2', width: '*'},
{field: 'firstData.col3', displayName: 'Column 3', width: 120},
{field: 'secondData.col2', displayName: 'Column 4', width: '*'},
{field: 'secondData.col3', displayName: 'Column 5', width: 120}
],
enableRowSelection: true,
onRegisterApi: function(gridApi) {
$scope.gridApi = gridApi;
}
};
$scope.gridOptions=finalObj;
}]);
Code : see the attaced Plunkr http://plnkr.co/edit/ZUyJQInnygirvfohIhQo
1) $scope.gridOptions=finalObj; needs to be changed to $scope.gridOptions.data=finalObj;
2) $scope.gridOptions.data needs an array.
Try this:
function merge(obj1, obj2){
return obj1.map(function(o1){
return Object.assign({}, o1, {
col4: obj2.find(function(o2){ return o1.col1 == o2.col1 }).col2,
col5: obj2.find(function(o2){ return o1.col1 == o2.col1 }).col3
})
})
}
var finalObj = merge(one, two);
$scope.gridOptions.data=finalObj;
Plunker

How to add values in an array inside an array in AngularJS

I apologize if my title sounds so confusing, as I don't know how to exactly word it. Basically, this is what I'm trying to do.
For example, I have the following array:
var sourceArray = [
{ question: "Question 1", inputType: "radio", answer: "Answer 1", id: "1" },
{ question: "Question 1", inputType: "radio", answer: "Answer 2", id: "2" },
{ question: "Question 1", inputType: "radio", answer: "Answer 3", id: "3" },
{ question: "Question 2", inputType: "radio", answer: "Answer 1", id: "4" },
{ question: "Question 2", inputType: "radio", answer: "Answer 2", id: "5" },
{ question: "Question 2", inputType: "radio", answer: "Answer 3", id: "6" }
]
I want to restructure this so that it'll look like this:
var newArray = [
{
question: "Question 1", inputType: "radio",
choices: [{answer: "Answer 1", id: "1"},
{answer: "Answer 2", id: "2"},
{answer: "Answer 3", id: "3"}
]},
{
question: "Question 2", inputType: "radio",
choices: [{answer: "Answer 1", id: "4"},
{answer: "Answer 2", id: "5"},
{answer: "Answer 3", id: "6"}
]}
]
Answers are grouped by question, so if the next question in the sourceArray is the same with the current, it will push the answers into the choices array.
Is this possible in AngularJS using angular.forEach?
Any help will be appreciated.
Thank you as always for your responses.
Here you go. See the working example below:
// Add a hepler method in the Array to find the value
Array.prototype.find = function(key, value) {
var index = -1;
angular.forEach(this, function(item, i) {
if (item[key] === value) {
index = i;
}
});
return this[index];
};
var app = angular.module("sa", []);
app.controller("FooController", function($scope) {
$scope.sourceArray = [{
question: "Question 1",
inputType: "radio",
answer: "Answer 1",
id: "1"
}, {
question: "Question 1",
inputType: "radio",
answer: "Answer 2",
id: "2"
}, {
question: "Question 1",
inputType: "radio",
answer: "Answer 3",
id: "3"
}, {
question: "Question 2",
inputType: "radio",
answer: "Answer 1",
id: "4"
}, {
question: "Question 2",
inputType: "radio",
answer: "Answer 2",
id: "5"
}, {
question: "Question 2",
inputType: "radio",
answer: "Answer 3",
id: "6"
}];
$scope.newArray = [];
$scope.convert = function() {
// Iterate array
angular.forEach($scope.sourceArray, function(item) {
// Check if the question alrady exists
if (!$scope.newArray.find('question', item.question)) {
// If not, push the question to the array with empty choices
$scope.newArray.push({
question: item.question,
inputType: item.inputType,
choices: []
});
}
var newArrayItem = $scope.newArray.find('question', item.question);
// Push the choices
newArrayItem.choices.push({
answer: item.answer,
id: item.id
});
});
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
<div ng-app="sa" ng-controller="FooController">
Before:
<br>{{sourceArray | json}}
<br>
convert
<br>After:
<br>{{newArray | json}}
</div>
You can group together using a for loop,
Here is the code:
function transformArr(orig) {
var newArr = [],
answers = {},
newItem, i, j, cur;
for (i = 0, j = orig.length; i < j; i++) {
cur = orig[i];
if (!(cur.question in answers)) {
answers[cur.question] = {question: cur.question, answers: [],inputType : cur.inputType,id :cur.id};
newArr.push(answers[cur.question]);
}
answers[cur.question].answers.push(cur.answer);
}
return newArr;
}
Working App
You need to filter in the sourceArray, the two Questions List as below:
var question1 = $filter('filter')(sourceArray, {
question: 'Question 1'
});
var question2 = $filter('filter')(sourceArray, {
question: 'Question 2'
});
After that, you should create a new data of array as below:
$scope.questionData = [{
"question": "Question 1",
"inputType": "radio",
"choices": []
}, {
"question": "Question 2",
"inputType": "radio",
"choices": []
}];
Then, you should run loops over the two filtered a variables into the new Array of object:
1):
angular.forEach(question1, function(value, key) {
if (value.question == $scope.questionData[0].question) {
$scope.questionData[0].choices.push({
'answer': value.answer,
'id': value.id
});
}
});
2):
angular.forEach(question2, function(value, key) {
if (value.question == $scope.questionData[1].question) {
$scope.questionData[1].choices.push({
'answer': value.answer,
'id': value.id
});
}
});
Refer here for demo:

Resources