Displaying multi dimensional array with ReactJS - javascript

Just started with ReactJS and I'm looking for the most efficient code to display the array below in a table structure as described in the 'render' section. I have been using .map to iterate through the users/buttons objects, but with no success yet.
In my code sample below, I want to take the userData array and display the content in separate rows (html table format)ie.
Joe,Smith,[Click 1A],[Click2B] //'Click XX' are buttons
Mary,Murphy,[Click 2A],[Click2B]
How can I achieve this?
Thanks
var MyButton = require('./mybutton.js');
var userData =[{
userButtons: [
[{user: [{ id: 1, lastName: 'Smith', firstName: 'Joe',
buttons: [
{button:[{ id:0, value: "Click 1A" enabled:1}]},
{button:[{ id:1, value: "Click 1B" enabled:1}]}
]
}]}],
[{user: [{ id: 1, lastName: 'Murphy', firstName: 'Mary',
buttons: [
{button:[{ id:0, value: "Click 2A" enabled:1}]},
{button:[{ id:1, value: "Click 2B" enabled:1}]}
]
}]
}]
]}];
var DisplayData = React.createClass({
render: function() {
// render userButtons in a table with data using <MyButton> ie.
// <table>
// <tr><td>Joe</td><td>Smith</td><td>[Click 1A]</td><td>[Click 2A]</td</tr>
// <tr><td>Mary</td><td>Murphy</td><td>[Click 2B]</td><td>[Click 2B]</td></tr>
// </table>
}
}
});
React.render(
<DisplayData tArr = {userData} />
, document.getElementById('content')
);
// mybutton.js
var React = require('react');
module.exports = React.createClass({
render: function() {
return (
<button>{this.props.value}</button>
)
}
});

I would suggest you simplify your userData if possible.. you have quite a bit of extra nested arrays that don't seem to be needed.
Something like this:
var userButtons = [
{
id: 1,
lastName: 'Smith',
firstName: 'Joe',
buttons: [
{
id: 0,
value: "Click 1A",
enabled: 1
}, {
id: 1,
value: "Click 1B",
enabled: 1
}
]
},
{
id: 2,
lastName: 'Murphy',
firstName: 'Mary',
buttons: [
{
id: 0,
value: "Click 2A",
enabled: 1
}, {
id: 1,
value: "Click 2B",
enabled: 1
}
]
}
];
Then it's easy to loop through and return the right elements:
return (
<table>
{
userButtons.map(function(ub) {
var buttons = ub.buttons.map(function(button) {
return (
<td>{button.value}</td>
)
});
return (
<tr>
<td>{ub.firstName}</td>
<td>{ub.lastName}</td>
{buttons}
</tr>
)
})
}
</table>
)

Something like the following might work:
handleClick: function(id, value) {
// do something
},
render: function() {
var rows = userData.userButtons.map(
function(u) {
var buttons = u.buttons.map(
function(b) {
return <Button onClick={function() { this.handleClick(b.id, b.value)}.bind(this);}
enabled={b.enabled===1}>
{b.value}
</Button>;
});
return <tr>
<td>{u.firstName}</td>
<td>{u.lastName}</td>
{buttons}
</tr>;
});
return <table>{rows}</table>;
}
Where I assume you can get Button from something like react-bootstrap.

Related

Omitting one or multiple values in javascript using lodash

I have a complex structure and I want to omit some properties from this structure for final value
let ListofWorlds = {
listOfCountries: [{
add: [{
id: 1,
updated: {
areacode: 123,
city: {
city: {'Austrailia'},
houses: {1000}
}
}
}], remove: []
}]
}
I want to omit city property from this structure and need this
let ListofWorlds = {
listOfCountries: [{
add: [{
id: 1,
updated: {
areacode: 123
}
}], remove: []
}]
}
This is what I have tried
let newListOfWorls = _.map(ListofWorlds, function (worlds) {
return _.omit(worlds, ['city']); })
Appreciate the help and knowledge
This is what i have tried.
let ListofWorlds = {
listOfCountries: [{
add: [{
id: 1,
updated: {
areacode: 123,
city: {
city: 'Austrailia',
houses: 1000
}
}
}], remove: []
}]}
const newList = ListofWorlds.listOfCountries.map(arr=>{
arr.add.forEach((item,index)=>{
arr.add[index] = _.omit(item,'updated.city')
})
return arr
})
Probably not the best way to do it, but hey it works, and why your code doesn't work probably you mapped an Object ListofWorlds and you need to be specific which field you want to be omitted

Create a key map for all paths in a recursive/nested object array

I have an n levels deep nested array of tag objects with title and ID. What I'm trying to create is a an object with IDs as keys and values being an array describing the title-path to that ID.
I'm no master at recursion so my attempt below doesn't exactly provide the result I need.
Here's the original nested tag array:
const tags = [
{
title: 'Wood',
id: 'dkgkeixn',
tags: [
{
title: 'Material',
id: 'ewyherer'
},
{
title: 'Construction',
id: 'cchtfyjf'
}
]
},
{
title: 'Steel',
id: 'drftgycs',
tags: [
{
title: 'Surface',
id: 'sfkstewc',
tags: [
{
title: 'Polished',
id: 'vbraurff'
},
{
title: 'Coated',
id: 'sdusfgsf'
}
]
},
{
title: 'Quality',
id: 'zsasyewe'
}
]
}
]
The output I'm trying to get is this:
{
'dkgkeixn': ['Wood'],
'ewyherer': ['Wood', 'Material'],
'cchtfyjf': ['Wood', 'Construction'],
'drftgycs': ['Steel'],
'sfkstewc': ['Steel', 'Surface'],
'vbraurff': ['Steel', 'Surface', 'Polished'],
'sdusfgsf': ['Steel', 'Surface', 'Coated'],
'zsasyewe': ['Steel', 'Quality']
}
So I'm building this recursive function which is almost doing it's job, but I keep getting the wrong paths in my flat/key map:
function flatMap(tag, acc, pathBefore) {
if (!acc[tag.id]) acc[tag.id] = [...pathBefore];
acc[tag.id].push(tag.title);
if (tag.tags) {
pathBefore.push(tag.title)
tag.tags.forEach(el => flatMap(el, acc, pathBefore))
}
return acc
}
const keyMap = flatMap({ title: 'Root', id: 'root', tags}, {}, []);
console.log("keyMap", keyMap)
I'm trying to get the path until a tag with no tags and then set that path as value for the ID and then push the items 'own' title. But somehow the paths get messed up.
Check this, makePaths arguments are tags, result object and prefixed titles.
const makePaths = (tags, res = {}, prefix = []) => {
tags.forEach(tag => {
const values = [...prefix, tag.title];
Object.assign(res, { [tag.id]: values });
if (tag.tags) {
makePaths(tag.tags, res, values);
}
});
return res;
};
const tags = [
{
title: "Wood",
id: "dkgkeixn",
tags: [
{
title: "Material",
id: "ewyherer"
},
{
title: "Construction",
id: "cchtfyjf"
}
]
},
{
title: "Steel",
id: "drftgycs",
tags: [
{
title: "Surface",
id: "sfkstewc",
tags: [
{
title: "Polished",
id: "vbraurff"
},
{
title: "Coated",
id: "sdusfgsf"
}
]
},
{
title: "Quality",
id: "zsasyewe"
}
]
}
];
console.log(makePaths(tags));

Generate a new array with count of property values

I have an array in my state :
projects: [
{ title: 'todo 1', person: 'Sam', status: 'ongoing'},
{ title: 'project', person: 'Jack', status: 'complete' },
{ title: 'Design video', person: 'Tim', status: 'complete' },
{ title: 'Create a forum', person: 'Jade', status: 'overdue' },
{ title: 'application', person: 'Jade', status: 'ongoing'},],
From this array (projects), I would like to generate a new array with Javascript and to get this result :
totalByPersonAndStatus : [
{person : 'Sam', complete: 0, ongoing: 1, overdue: 0 },
{person : 'Jack', complete: 1, ongoing: 0, overdue: 0 },
{person : 'Tim', complete: 1, ongoing: 0, overdue: 0 },
{person : 'Jade', complete: 0, ongoing: 1, overdue: 1 },]
I tried it
totalProjectsByPersonAndStatus: state => {
state.projects.forEach(name => {
state. totalByPersonAndStatus["name"] = name.person;
});
return state. totalByPersonAndStatus;
The problem, if a make a console.log(this.totalByPersonAndStatus) I have an object with only the data of projects.name [name: "Jade", __ob__: Observer]
Can you help me ?
Thank you
You can use reduce
let projects =[{title:'todo1',person:'Sam',status:'ongoing'},{title:'project',person:'Jack',status:'complete'},{title:'Designvideo',person:'Tim',status:'complete'},{title:'Createaforum',person:'Jade',status:'overdue'},{title:'application',person:'Jade',status:'ongoing'},]
let desired = projects.reduce((output,{person,status}) => {
if( output[person] ){
output[person][status]++
} else {
output[person] = {
person,
complete: Number(status==='complete'),
ongoing: Number(status==='ongoing'),
overdue: Number(status==='overdue')
}
}
return output;
},{})
console.log(Object.values(desired))
Create a new Set for people and statuses by iterating through the projects, a set has only unique values so sets are a convenience, iterate through your people set creating a new object with all the statuses initialized to 0, then iterate over the projects to increment the various statuses that apply. This method allows any number of new statuses to be added without changing the code - dynamic.
var people = new Set();
var status = new Set();
projects.forEach((p)=>{
people.add(p.person);
status.add(p.status);
});
var totalByPersonAndStatus = [];
people.forEach((person)=>{
let peeps = { "person": person };
status.forEach((stat)=>{
peeps[stat] = 0;
});
projects.forEach((project)=>{
if (project.person === person) { peeps[project.status]++; }
});
totalByPersonAndStatus.push(peeps);
});
You could use reduce and destructuring like this:
const projects=[{title:'todo 1',person:'Sam',status:'ongoing'},{title:'project',person:'Jack',status:'complete'},{title:'Design video',person:'Tim',status:'complete'},{title:'Create a forum',person:'Jade',status:'overdue'},{title:'application',person:'Jade',status:'ongoing'}]
const merged = projects.reduce((acc,{person,status})=>{
acc[person] = acc[person] || { person, ongoing:0, complete:0, overdue:0}
acc[person][status]++;
return acc;
},{})
console.log(Object.values(merged))
The goal is create an object merged with each person as key and then increment based on the statuses:
{
"Sam": {
"person": "Sam",
"ongoing": 1,
"complete": 0,
"overdue": 0
},
"Jack": {
}
...
}
Then use Object.values, to get the final array.
You could make it a one-liner:
const projects=[{title:'todo 1',person:'Sam',status:'ongoing'},{title:'project',person:'Jack',status:'complete'},{title:'Design video',person:'Tim',status:'complete'},{title:'Create a forum',person:'Jade',status:'overdue'},{title:'application',person:'Jade',status:'ongoing'}],
output = Object.values(projects.reduce((a,{person,status})=>
((a[person] = a[person] || {person,ongoing:0,complete:0,overdue:0})[status]++,a),{}))
console.log(output)

Merge the object using typescript

In my angular application i am having the data as follows,
forEachArrayOne = [
{ id: 1, name: "userOne" },
{ id: 2, name: "userTwo" },
{ id: 3, name: "userThree" }
]
forEachArrayTwo = [
{ id: 1, name: "userFour" },
{ id: 2, name: "userFive" },
{ id: 3, name: "userSix" }
]
newObj: any = {};
ngOnInit() {
this.forEachArrayOne.forEach(element => {
this.newObj = { titleOne: "objectOne", dataOne: this.forEachArrayOne };
})
this.forEachArrayTwo.forEach(element => {
this.newObj = { titleTwo: "objectTwo", dataTwo: this.forEachArrayTwo };
})
console.log({ ...this.newObj, ...this.newObj });
}
In my real application, the above is the structure so kindly help me to achieve the expected result in the same way..
The working demo https://stackblitz.com/edit/angular-gyched which has the above structure.
Here console.log(this.newObj) gives the last object,
titleTwo: "ObjectTwo",
dataTwo:
[
{ id: 1, name: "userFour" },
{ id: 2, name: "userFive" },
{ id: 3, name: "userSix" }
]
but i want to combine both and need the result exactly like the below..
{
titleOne: "objectOne",
dataOne:
[
{ id: 1, name: "userOne" },
{ id: 2, name: "userTwo" },
{ id: 3, name: "userThree" }
],
titleTwo: "ObjectTwo",
dataTwo:
[
{ id: 1, name: "userFour" },
{ id: 2, name: "userFive" },
{ id: 3, name: "userSix" }
]
}
Kindly help me to achieve the above result.. If i am wrong in anywhere kindly correct with the working example please..
You're assigning both values to this.newObj, so it just overwrites the first object.
Also, there is no need for your loop. It doesn't add anything.
Instead, you can do:
this.newObjA = { titleOne: "objectOne", dataOne: this.forEachArrayOne };
this.newObjB = { titleTwo: "objectTwo", dataTwo: this.forEachArrayTwo };
console.log({ ...this.newObjA, ...this.newObjB });
**
EDIT **
Having spoken to you regarding your requirements, I can see a different solution.
Before calling componentData, you need to make sure you have the full data. To do this, we can use forkJoin to join the benchmark requests, and the project requests into one Observable. We can then subscribe to that Observable to get the results for both.
The code would look something like this:
createComponent() {
let benchmarks, projects;
let form = this.productBenchMarkingForm[0];
if (form.benchmarking && form.project) {
benchmarks = form.benchmarking.filter(x => x.optionsUrl)
.map(element => this.getOptions(element));
projects = form.project.filter(x => x.optionsUrl)
.map(element => this.getOptions(element));
forkJoin(
forkJoin(benchmarks), // Join all the benchmark requests into 1 Observable
forkJoin(projects) // Join all the project requests into 1 Observable
).subscribe(res => {
this.componentData({ component: NgiProductComponent, inputs: { config: AppConfig, injectData: { action: "add", titleProject: "project", dataProject: this.productBenchMarkingForm[0] } } });
})
}
}
getOptions(element) {
return this.appService.getRest(element.optionsUrl).pipe(
map((res: any) => {
this.dataForOptions = res.data;
element.options = res.data;
return element;
})
)
}
Here is an example in Stackblitz that logs the data to the console

Angular js filter array inside array

I am having a hard time doing an Angular filter to solve a problem as below.
The filter logic is as below:
1) If all listItem of that item has qtyLeft != 0, do not display that item
2) If any of the listItem of that item has qtyLeft == 0, display the item title as well as coressponding listItem that have qtyLeft == 0
Here's a basic example of my data structure, an array of items:
$scope.jsonList = [
{
_id: '0001',
title: 'titleA',
list: {
listName: 'listNameA',
listItem: [
{
name: 'name1',
qtyLeft: 0
},
{
name: 'name2',
qtyLeft: 0
},
]
}
},
{
_id: '0002',
title: 'titleB',
list: {
listName: 'listNameB',
listItem: [
{
name: 'name3',
qtyLeft: 2
},
{
name: 'name4',
qtyLeft: 0
},
]
}
},
{
_id: '0003',
title: 'titleC',
list: {
listName: 'listNameC',
listItem: [
{
name: 'name5',
qtyLeft: 2
},
{
name: 'name6',
qtyLeft: 2
},
]
}
},
]
Here is the final expected outcome:
<div ng-repeat="item in jsonList | filter: filterLogic">
<div> </div>
</div>
// final outcome
<div>
<div>Title: titleA, ListItem: Name1, Name2</div>
<div>Title: titleB, ListItem: Name4</div>
</div>
Created working Plunkr here. https://plnkr.co/edit/SRMgyRIU7nuaybhX3oUC?p=preview
Do not forget to include underscore.js lib in your project if you are going to use this directive.
<div ng-repeat="jsonItem in jsonList | showZeroElement track by $index">
<div>Title:{{ jsonItem.title}}, ListItem:<span ng-repeat="item in
jsonItem.list.listItem track by $index" ng-if="item.qtyLeft==0">
{{item.name}}</span>
</div>
</div>
And
app.filter('showZeroElement', function() {
return function(input) {
var items = []
angular.forEach(input, function(value, index) {
angular.forEach(value.list.listItem, function(val, i) {
var found = _.findWhere(items, {
'title': value.title
})
if (val.qtyLeft === 0 && found === undefined) {
items.push(value)
}
})
})
return items
}
})

Categories

Resources