Javascript pivoting data and generating dynamic table from object - javascript

I am receiving a data object of results that have been pivoted and I am unable to change the structure that is returned to me. My only option at this point is to manipulate the data to parse it how I need to.
Here is what my results look like:
// Object from service
let dataObj = [{
CostCenter: '12345',
HasLevel1Access: 'No',
HasLevel2Access: 'No',
HasLevel3Access: 'Yes',
FirstName: 'Bob',
LastName: 'Jones',
UID: '12345'
},
{
CostCenter: '555',
HasLevel1Access: 'Yes',
HasLevel2Access: 'No',
HasLevel3Access: 'Yes',
FirstName: 'Tommy',
LastName: 'C',
UID: '6789'
},
{
CostCenter: '51112',
HasLevel1Access: 'Yes',
HasLevel2Access: 'No',
HasLevel3Access: 'Yes',
FirstName: 'Smithson',
LastName: 'J',
UID: '8888'
}];
From this data, I need to make a table. The trick here is that I need to use some of the property names as the column headers but exclude others.
My table is very basic, it contains the persons name and then all of the dynamic column names:
<table class="table table-condensed" border="1">
<thead>
<tr>
<th>Employee Name</th>
<th *ngFor="let m of columnNames">{{ m }}</th>
</tr>
</thead>
<tbody>
<!-- Example Record 0 -->
<tr>
<td>Bob Jones</td>
<td>No</td>
<td>No</td>
<td>Yes</td>
</tr>
<!-- Example Record 0 -->
</tbody>
</table>
The first thing I did in order to get the column names is create an array of the IgnoreColumns which is the property names I wan't to exclude from being its own column in the table.
// Hold all of the column names
private columnNames = [];
// Ignore these columns, they dont get printed as headers
private ignoreColumns = ['CostCenter', 'FirstName', 'LastName', 'UID'];
I then looped over the first record in the result set and pushed all of the property names to an array that are not in our ignoreColumns array. This leaves me with a unique array of the dynamic columns.
// Find all the keys in our first result
for (var p in dataObj[0]) {
// Get the key names
if (dataObj[0].hasOwnProperty(p)) {
// If this key name doesnt already exist in the array AND its not in our ignored list push them to our array
if (!_.includes(this.columnNames, p) && !_.includes(this.ignoreColumns, p)) {
this.columnNames.push(p);
}
}
}
I am stuck at this point. I was able to create the table structure with the headings in place but I don't know how I should proceed to get the data aligned under the correct columns in the table.
This is what I am going for in my final output:
<table class="table table-condensed" border="1">
<thead>
<tr>
<th>Individual</th>
<th>HasLevel1Access</th>
<th>HasLevel2Access</th>
<th>HasLevel3Access</th>
</tr>
</thead>
<tbody>
<tr>
<td>Bob Jones</td>
<td>No</td>
<td>No</td>
<td>Yes</td>
</tr>
<tr>
<td>Tommy C</td>
<td>Yes</td>
<td>No</td>
<td>Yes</td>
</tr>
<tr>
<td>Smithson J</td>
<td>Yes</td>
<td>No</td>
<td>Yes</td>
</tr>
</tbody>
</table>
Here is a plunkr of where I am at: http://plnkr.co/edit/9WygBXsQaDaxTMudb7ZB?p=preview
Any advice on how to approach this?

What about
<tr *ngFor="let item of dataObj">
<td>{{item.FirstName}} {{item.LastName}}</td>
<td *ngFor="let m of columnNames">{{item[m]}}</td>
</tr>
Working demo

You meant something like this?
<tr *ngFor="let data of dataObj">
<td>{{data.FirstName+" "+data.LastName}}</td>
<td>{{data.HasLevel1Access}}</td>
<td>{{data.HasLevel2Access}}</td>
<td>{{data.HasLevel3Access}}</td>
</tr>
http://plnkr.co/edit/EHsVFaiaK1UUcWrbm6zX?p=preview

Related

Javascript Vue 3 Extract data from an array and display into a table

Hello everyone hope you having a great day,
I have setup a front end app on Vue Js linked with an express.js api which connects to a mysql database. I use axios for sending http requests. I am able to grab the data from my mysql database and console.log it into the front end system.
However I am struggling to extract the data from the array and display it into the table.
This is the table.
<table class="table">
<thead>
<tr>
<th scope="col">#ID</th>
<th scope="col">First</th>
<th scope="col">Last</th>
<th scope="col">email</th>
<th scope="col">DOB</th>
<th scope="col">Country Of Residence</th>
<th scope="col">Phone Number</th>
<th scope="col">Contact_Via Phone</th>
<th scope="col">Contact Via Email</th>
<th scope="col">Contact Via Mail</th>
<th scope="col">Sign up date</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row" v-for="name in newData" :key="newData.id"></th>
<td>Mark</td>
<td>Otto</td>
<td>#mdo</td>
</tr>
<tr>
<th scope="row">2</th>
<td>Jacob</td>
<td>Thornton</td>
<td>#fat</td>
</tr>
<tr>
<th scope="row">3</th>
<td colspan="2">Larry the Bird</td>
<td>#twitter</td>
</tr>
</tbody>
</table>
This is where I grab the data from the database when the page is created.
async created() {
try {
const getUserData = await axios.get('/api/getstudentdata', {})
.then(getUserData => getUserData.data)
{
this.newData = JSON.parse(JSON.stringify(getUserData))
for( let i = 0; i < this.newData.length; i++) {
console.log(this.newData[i].Name)
}
}
}catch(error) {
console.log(error)
}
},
Here I have added what my console logs and what the vue dev tools say.
https://imgur.com/a/eIHDq6u
console logs:
roxy {0: {…}, 1: {…}, 2: {…}}
[[Handler]]: Object
[[Target]]: Array(3)
0: {ID: 50, Name: 'Bob', Surname: 'Bobbob', Email: 'bob#gmail.com', DOB: '2000-07-15', …}
1: {ID: 51, Name: 'Tony', Surname: 'Scrub', Email: 'badatcoding#gmail.com', DOB: '2000-07-15', …}
2: {ID: 52, Name: 'Onemoreuser', Surname: 'te4st', Email: 'testoding#gmail.com', DOB: '2000-07-15', …}
length: 3
[[Prototype]]: Array(0)
[[IsRevoked]]: false
Dev tools:
newData:Array[3]
0:Reactive
ID:50
Name:"Bob"
Surname:"Bobbob"
Email:"bob#gmail.com"
DOB:"2000-07-15"
Country_of_residence:"London"
Phonenumber:"0749432423"
contact_phone:"true"
contact_email:"true"
sign_up_date:"2022-07-19T14:06:19.000Z"
Timezone:"GMT+1"
1:Reactive
2:Reactive
Update! I managed to display all the data to the table however I cant extract just the ID or the Name... here is photo of result.
https://imgur.com/a/3pqDrML
First of all, in a v-for loop, keys must be unique and newData.id is not a valid key, I guess you wanted to use something like:
v-for="item in newData" :key="item.id"
Secondly ,you're using v-for in the wrong place and you are not using vue mustaches to use dynamic variables. Try this one:
<tr v-for="item in newData" :key="item.id">
<td>{{item.ID}}</td>
<td>{{item.Name}}</td>
<td>{{item.Surname}}</td>
...
</tr>

How can I search (and filter out) data inside a nested table with datatables?

I am working with a table that has two rows: the header row and then the body row. In the body row, each column contains another table. Like this:
<table id="example">
<thead>
<tr>
<td>Col A</td>
<td>Col B</td>
<td>Col C</td>
</tr>
</thead>
<tbody>
<tr>
<td valign="top">
<table>
<tr>
<td>Data</td>
<td>Data2</td>
</tr>
</table>
</td>
<td valign="top">
<table>
<tr>
<td>Data3</td>
<td>Data4</td>
</tr>
</table>
</td>
<td valign="top">
<table>
<tr>
<td>Data5</td>
<td>Data6</td>
</tr>
</table>
</td>
</tr>
</tbody>
</table>
I have my datatable setup like this:
<script type="text/javascript">
const columns = [
{ title: '' },
]
let table = $('#example').DataTable({
createdRow: function(row) {
$(row).find('td table')
.DataTable({
columns: columns,
dom: 'tf'
})
}
})
</script>
The problem is that when I search for something, I want ALL the tables (including the nested ones) to filter out the results. So in my code above, as an example, if I search for "Data2", I would expect the second and third columns to become empty and just one result appear in the first column. However, at present, since "Data2" is found in this row (of which there is only one in this table), it simply returns ALL the data.
I found a REALLY good example that is close to what I want (which I what my current code is based on):
http://jsfiddle.net/davidkonrad/8pzkr6yn/
If we use the example from the JSFiddle, you can see searching for "722" returns only the last row, but still all the results from each nested table from within that row are there. I'd like it so that searching 722 globally will return the results as if 722 was searched individually in each column.
How can I adjust the code to make it so that all the nested tables get filtered out, not just the main table?
Bonus points if we can eliminate the search box in every nested datatable!

ng-repeat issue with JSON Object

So I'm trying to print the keys and values of a simple JSON object inside an HTML table with ng-repeat but not able to print it on the html page. The JSON object has been received from the backend and am trying to populate that in the frontend. I understand that I am doing a silly mistake somewhere but can't understand where.
JSON Object
json_data ={
user1 : "matt",
user2 : "kim",
user3 : "Tim"
}
$scope.rows = json_data;
HTML code..
<table ng-if="displayTable">
<caption>Results</caption>
<tr>
<th>Username</th>
<th>Name</th>
</tr>
<tr ng-repeat="(key, value) in rows">
<td> {{key}} </td> <td> {{ value }} </td>
</tr>
</tr>
</table>
Can't understand what silly mistake I am doing here.
Try {{rows.key}} and {{rows.value}}. Although I don't thing this is the answer. Give it a try..
Alternative ly you can try to see if it works with just one , either key or value...
First at all, the (key, value) is more well represented by (index, value).
A correct version of this piece of code will output this:
0 {"user1":"matt","user2":"kim","user3":"Tim"}
which 0 is the first index of an array and the json is the entire value.
So, i guess you are using a bad approach.
Try to modify your array to something like that:
$scope.rows = [
{key: 'user1', user: 'matt'},
{key: 'user1', user: 'kim'},
{key: 'user1', user: 'Tim'},
];
And modify your HTML to:
<table ng-if="displayTable">
<caption>Results</caption>
<tr>
<th>Username</th>
<th>Name</th>
</tr>
<tr ng-repeat="row in rows">
<td> {{row.key}} </td> <td> {{ row.user }} </td>
</tr>
</tr>
</table>

Angular search for combined key

Say you have the following object:
var user: {firstname: 'Marc', lastname:'Ras', age:30};
You have alot of these objects in an array called: user_array
Now you wish to display them in a table so you create your table:
<table>
<thead>
<th>Full name</th>
<th>Age</th>
</thead>
<tbody>
<tr ng-repeat="user in user_array">
<td>{{user.firstname + ' '+user.lastname}}</td>
<td>{{user.age}}</td>
</tr>
</tbody>
</table>
Now you wish to create an input field where you can search for a user's full name:
And here is kinda ends for me :S how is it possible to search for a combinded key? normally you would have:
<input type="text" ng-model="search.fieldname" />
However you cant do that here since the field is combined of two fieldnames?
add this to your controller
$scope.filterNameLastName = function (user) {
var fullname = user.firstname + ' '+ user.lastname;
if(fullname == $scope.searchParamater)
return true;
else
return false;
};
and add filter to ng-repeat
<table>
<thead>
<th>Full name</th>
<th>Age</th>
</thead>
<tbody>
<tr ng-repeat="user in user_array | filter:filterNameLastName ">
<td>{{user.firstname + ' '+user.lastname}}</td>
<td>{{user.age}}</td>
</tr>
</tbody>
</table>
This should give you an idea on how custom filters work. I haven't tested the code so you may have to do some modifications.

Use of rowspan to group hierarchical data

Is it possible to group data (using rowspan as explained here) in a table rendered with angularjs. Data is hierarchical, with state having many counties and each counties has multiple zipcodes. I want a table with only column for state, county, zip etc (so give a rowspan for length of the collection). I am not sure ng-repeat-start and ng-repeat-end can be used to achieve this. Please see the starter template here
<table>
<thead>
<tr>
<th>State</th>
<th>County</th>
<th>Zip</th>
</tr>
</thead>
<tbody>
<tr ng-repeat='st in states'>
<td>{{st.name}}</td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
data
var oh_counties = [
{name: "Franklin", zips: [111,222,333,444,555]},
{name: "Adams", zips: [111,222,333,444]},
{name: "Allen", zips: [111,222,333]}
],
wi_counties = [
{name: "Dane", zips: [111]},
{name: "Adams", zips: [111,222,333,444]}
]
$scope.states = [
{name: "OH", counties: oh_counties},
{name: "WI", counties: wi_counties},
];
Edit:
A handcrafted version of the desired output is here http://plnkr.co/edit/T7toND0odx6qr8mVC121?p=preview
This is a variant of Holly Cummins' answer. The repeat is moved into the tr with ng-repeat-start and ng-repeat-end to prevent the tbody from being repeated. Also uses a slightly different method to hide the first row.
<tbody>
<tr ng-repeat-start='st in states'>
<th rowspan="{{st.counties.length}}">{{st.name}}</th>
<td>{{st.counties[0].name}}</td>
</tr>
<tr ng-repeat-end ng-repeat='county in st.counties' ng-hide="$first">
<td>{{county.name}}</td>
</tr>
</tbody>
This variant of KayakDave's answer improves the structuring by pulling the first nested row out to share the <tr> of the header:
<tbody ng-repeat='st in states'>
<tr>
<th rowspan="{{st.counties.length}}">{{st.name}}</th>
<td>{{county[0].name}}</td>
</tr>
<tr ng-repeat='county in st. counties' ng-show="$index > 0">
<td>{{county.name}}</td>
</tr>
</tbody>
Sure. Is something like this what you had in mind:
<tbody ng-repeat='st in states'>
<td rowspan="{{st.counties.length+1}}">{{st.name}}</td>
<tr ng-repeat='county in st.counties'>
<td>{{county.name}}</td>
</tr>
</tbody>
I kept this example simple, nested 2 deep. But in the fiddle, below, I've got it nested 3 deep (so it includes zip).
demo fiddle
This may be usefull
<table>
<tbody ng-repeat='st in states'>
<tr>
<th >{{st.name}}</th>
<td>
<table>
<tr ng-repeat='county in st.counties'>
<td>{{county.name}}</td>
<td>
<table>
<tr ng-repeat='zip in county.zips'>
<td>{{zip}}</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</tbody>
</table>

Categories