0

I have the following class that gets sent as an IEnumerable from an API:

public class LogsDto
{
    public decimal Value { get; set; }
    public DateTime Time_Stamp { get; set; }
    public string TagName { get; set; }

}

This is the Angular class that the data is passed into as an array:

export class Logs {
    value: number;
    timestamp: string;
    tagName: string;
}

Sample data will come across as so:

{ "value": 100, "time_Stamp": "2017-05-04T00:07:47.407", "tagName": "Tag 1" },
{ "value": 200, "time_Stamp": "2017-05-04T00:07:47.407", "tagName": "Tag 2" },
{ "value": 300, "time_Stamp": "2017-05-04T00:07:47.407", "tagName": "Tag 3" },
{ "value": 150, "time_Stamp": "2017-05-04T00:07:57.407", "tagName": "Tag 1" },
{ "value": 250, "time_Stamp": "2017-05-04T00:07:57.407", "tagName": "Tag 2" },
{ "value": 350, "time_Stamp": "2017-05-04T00:07:57.407", "tagName": "Tag 3" }

In Angular, I want to turn this into a table that is read like so:

<table>
    <th>Time_Stamp</th> <th>Tag 1</th> <th>Tag 2</th> <th>Tag 3</th>

    <td>2017-05-04T00:07:47.407</td> <td>100</td> <td>200</td> <td>300</td>

    <td>2017-05-04T00:07:45.407</td> <td>150</td> <td>250</td> <td>350</td>
</table>

I can hard code it fine as shown above. The problem I am having is I don't know how to parse the data from columns to rows. The "tagName" property will not always be the same. Sometimes there will be 10 different tag names.

Any help is appreciated.

Michael Smith
  • 53
  • 1
  • 7

2 Answers2

0

A quick way to solve it would be to find all the unique properties off the objects being returned through reflection and store them. Then you could render out a header, then render each object and access via the columns in a nested set of ngFors. This, of course, requires the ordering to remain the same as you evaluate over the columns, incidentally. You'll also want to perform a projection of your data to perform something like a pivot. Then we will perform a group by of the data by timestamp and for that we will 100% steal someone else's SO group by function.

The control order is pivot then column header eval.

The column eval:

generateColumnHeaders(myObjectArray) {
this.columns = [];
for(var i = 0; i < myObjectArray.length; ++i) {
  for(var col in myObjectArray[i]) {
      if(myObjectArray[i].hasOwnProperty(col)) {
        if(this.columns.findIndex(colmn => colmn === col) === -1) {
          this.columns.push(col);
        }
      }
    }
  }
}

The pivot and other transforms:

transformArray(objectArray, accessObject) {
    return this.groupByArray(objectArray.map(obj =>
    {
      var tagNameString = obj.tagName;
      let tempObj = {};
      tempObj[accessObject.pivotColumn] = obj.time_Stamp;
      tempObj[obj.tagName] = obj.value;
      return tempObj;
    }), accessObject.pivotColumn).map(tsg => {
      let tempObj = {};
      tempObj[accessObject.pivotColumn] = tsg.time_Stamp;
      for(var i = 0; i < tsg.values.length; ++i) {
        for(var tag in tsg.values[i]) {
          if(tag.indexOf(accessObject.dynamicColumnCommon !== -1)) {
            tempObj[tag] = tsg.values[i][tag];
          }
        }
      }

      return tempObj;
    });
}

Controlling code:

this.myObjectArray = this.transformArray(this.myObjectArray, { pivotColumn: "time_Stamp", dynamicColumnCommon:"Tag"});

this.generateColumnHeaders(this.myObjectArray);

The template evaluation:

<table>
<tr>
  <th *ngFor="let column of columns">{{column}}</th>
  </tr>
  <tr *ngFor="let obj of myObjectArray">
    <td *ngFor="let column of columns">{{obj[column]}}</td>
  </tr>
</table>

Plunker

silentsod
  • 8,165
  • 42
  • 40
  • This works for displaying the data as it is in the Logs[]. If you look at my original question, I want the column headers to be the unique values of the "tagName" property as well as the "time_stamp". Each tagName will always have only 1 matching time_stamp across all of the tagNames. They are stored in the database like that. – Michael Smith May 26 '17 at 13:40
0

This is how I ended up making it work. It is pretty fast, but I am sure I am not doing it the most efficient way. Would appreciate constructive criticism.

parseLogs(logs: Logs[]): void {
const ts: string[] = logs.map(data => data.time_Stamp.toString());
var timestamps = ts.filter((x, i, a) => x !== undefined && a.indexOf(x) === i);


var jsonString: string = '[';

for (var j = 0; j < timestamps.length; j++) {
  var date = new Date(timestamps[j]);
  var hours = date.getHours().toString();
  if (date.getHours() < 10)
    hours = '0' + hours;
  var minutes = date.getMinutes().toString();
  if (date.getMinutes() < 10)
    minutes = '0' + minutes;

  var dtString: string = (date.getMonth() + 1) + '-' + date.getDate() + '-' + date.getFullYear() + ' ' + date.getHours() + ':' + date.getMinutes();

  jsonString = jsonString + '{"Time Stamp":"' + dtString + '"';

  for (var i = 0; i < logs.length; i++) {
    if (logs[i].time_Stamp === timestamps[j])
      jsonString = jsonString + ',"' + logs[i].tagName + '":' + logs[i].value + '';
  }

  if (j === (timestamps.length - 1)) {
    console.log('j:' + j + 'logs.length:' + logs.length.toString());
    jsonString = jsonString + '}';
  } else {
    console.log('j:' + j + 'logs.length:' + logs.length.toString());
    jsonString = jsonString + '},';
  }
}

jsonString = jsonString + ']';

console.log(jsonString);

this.myLogs = JSON.parse(jsonString);

//From example shown above
this.generateColumnHeaders(this.myLogs);
Michael Smith
  • 53
  • 1
  • 7