Pixic Pixic - 4 months ago 12
AngularJS Question

Multi-level tables (inside another if clicked)

Scenario



Lets say I am owner of a big company that has many stores. Depending on what role (place in the organization) I have within the company, I will have different access to data. There will be different modules and for this specific question there is one where users that have access can go through daily cost and sales.
(If that's legal or not...don't care, it's just for an example.)

The user thereby get all data through REST API from BackEnd (Java application) with all data for all stores the user has access to. The user should then be able to filter the data, by different filter combinations. Most relevant for my question is the date interval by days.

There will be some charts showing data on different levels and below there will be a table area where I want the multi-level tables, hence my question.

Done so far




  1. I first created accordions that have stores on accordion-group level and then next level of data in a table, within the accordion-body. (Only hard coded data at the moment.) The problem here was that an according heading is a string and after some discussion we felt that this was not a good solution since the heading would consist of parts of data that in a table would have been separate columns. It would therefore be difficult to "columnize" the heading data to match horizontally the different "stores" (between the accordion headings) when collapsed (and of course even more messy when one or more accordion are expanded).

  2. I replaced the accordions with table and ng-repeat. Have successfully populated the first table level with both data from the figurative API with JSON data as well as got i18next working for the headings.



JSON



{
"metadata":{
"storesInTotal":"25",
"storesInRepresentation":"2"
},
"storedata":[
{
"store" : {
"storeId" : "1000",
"storeName" : "Store 1",
"storePhone" : "+46 31 1234567",
"storeAddress": "Some street 1",
"storeCity" : "Gothenburg"
},
"data" : {
"startDate" : "2013-07-01",
"endDate" : "2013-07-02",
"costTotal" : "100000",
"salesTotal" : "150000",
"revenueTotal" : "50000",
"averageEmployees" : "3.5",
"averageEmployeesHours" : "26.5",
"dayData" : [
{
"date" : "2013-07-01",
"cost" : "25000",
"sales" : "15000",
"revenue" : "4000",
"employees" : "3",
"employeesHoursSum" : "24"
},
{
"date" : "2013-07-02",
"cost" : "25000",
"sales" : "16000",
"revenue" : "5000",
"employees" : "4",
"employeesHoursSum" : "29"
}
]
}
},
{
"store" : {
"storeId" : "2000",
"storeName" : "Store 2",
"storePhone" : "+46 8 9876543",
"storeAddress": "Big street 100",
"storeCity" : "Stockholm"
},
"data" : {
"startDate" : "2013-07-01",
"endDate" : "2013-07-02",
"costTotal" : "170000",
"salesTotal" : "250000",
"revenueTotal" : "80000",
"averageEmployees" : "4.5",
"averageEmployeesHours" : "35",
"dayData" : [
{
"date" : "2013-07-01",
"cost" : "85000",
"sales" : "120000",
"revenue" : "35000",
"employees" : "5",
"employeesHoursSum" : "38"
},
{
"date" : "2013-07-02",
"cost" : "85000",
"sales" : "130000",
"revenue" : "45000",
"employees" : "4",
"employeesHoursSum" : "32"
}
]
}
}
],
"_links":{
"self":{
"href":"/storedata/between/2013-07-01/2013-07-02"
}
}
}


Visual example - JSFiddle



Check the values in the result frame, top left corner. Try clicking for example row with Store ID 2000, then with 3000 and then 3000 again to see how the values change.
Current update of my JSFiddle

Wanted functionality



When a row is clicked (as shown in the JSFiddle), I want a directive or something triggered, to go and fetch underlying data (dayData) for the store clicked and show all days in the date interval. I.e expanding the row, and including a new table under the clicked row, which also should use ng-repeat to get all data displayed similar to the existing one, but inline.

Question



So I have already got the functionality to get the $index and also the specific data from the clicked row.
What kind of directive or any other solution do I need additionally to get the "data when row clicked" and presented in a table under the clicked row?

I don't want it in the DOM all the time, since there might be many dayData for each store and many stores. (And will use pagination later, but even so, not in the DOM all the time.)
This means that I have to be able to ADD when clicking a row, and when clicking the same or another REMOVE from the previously clicked.




EDIT



New updated JSFiddle.

Answer

The requirement was to not fill the DOM with all second level tables and I came up with a solution for it.

First I tried creating a custom directive and I got it to insert a row at the right place (beneath the clicked row) and created a second level table with headers but could not get it to populate with rows using ng-repeat.

Since I could not find a solution that worked fully I went back to what I already had created, with ng-show and sought a solution like it...and there exist one. Instead of using ng-show/ng-hide, Angular has a directive called ng-switch.

In level one

<tbody data-ng-repeat="storedata in storeDataModel.storedata" 
       data-ng-switch on="dayDataCollapse[$index]">

...and then in the second level, i.e. the second tr

<tr data-ng-switch-when="true">

, in which you have the second level ng-repeat.

Here's a new JSFiddle.

Inspect elements, and you will see that there is a comment placeholder for each "collapsed" level 2 table.


UPDATE (2014-09-29)

Upon request of also expanding/collapsing level 3, here's a new JSFIDDLE.

NOTE! - This solution have all information in the DOM at all times, i.e. not as the earlier solution, which only added a notation for where the information should be added upon request.

(I can't take credit of this one though, since my friend Axel forked mine and then added the functionality.)

Comments