Reputation: 273
I need some help to render a html table using an Angular model.
First, I have a model that specifies that I need to render a table, and a list of the "questions" that needs to be shown in the table.
Data example:
{
"Id": 25546,
"questionType": "Table",
"maxRows": 2,
"maxCols": 3,
"questionsInTable": [{
"isActive": true,
"questionText": "Table Title",
"validation": "false",
"rowPosition": 1,
"colPosition": 1,
"isPrintable": true,
"Answer": null,
"Type": "Label"
}, {
"isActive": true,
"questionText": "2014",
"validation": "false",
"rowPosition": 1,
"colPosition": 2,
"isPrintable": true,
"Answer": null,
"Type": "Label"
}, {
"isActive": true,
"questionText": "2013",
"validation": "false",
"rowPosition": 1,
"colPosition": 3,
"isPrintable": true,
"Answer": null,
"Type": "Label"
}, {
"isActive": true,
"questionText": "Another description here",
"validation": "false",
"rowPosition": 2,
"colPosition": 1,
"isPrintable": true,
"Answer": null,
"Type": "Label"
}, {
"isActive": true,
"questionText": "DescFor2014",
"validation": "true",
"rowPosition": 2,
"colPosition": 2,
"isPrintable": true,
"Answer": null,
"Type": "InputText"
}, {
"isActive": true,
"questionText": "DescFor2013",
"parentQuestion": 25546,
"validation": "true",
"rowPosition": 2,
"colPosition": 3,
"isPrintable": true,
"Answer": null,
"Type": "InputText"
}]
}
Each item (or question) is providing the row and column position in the table, also the data has two items with the Max of rows and columns. I'm able to create the table using MaxRows and MaxCols data, but I'm struggling to insert the question in the correct cell.
The result should be the example above:
Render output example:
<table>
<tr>
<td>Table Title</td>
<td>2014</td>
<td>2013</td>
</tr>
<tr>
<td>Another description here</td>
<td>DescFor2014</td>
<td>DescFor2013</td>
</tr>
</table>
Is there a way to perform this?.
I'll appreciate your help, or if you could point me in the right direction.
Upvotes: 2
Views: 319
Reputation: 3871
Please refer to this Plunk: http://plnkr.co/edit/xTagjy1n9tl0CvnDH5Q3?p=preview
You basically have to ng-repeat the rows till maxRows and ng-repeat the cols till maxCols:
<table>
<tr ng-repeat="i in [] | range:(tableData.maxRows)">
<td ng-repeat="j in [] | range:(tableData.maxCols)">
{{tableData.questionsInTable[j + i*tableData.maxCols].questionText}}
</td>
</tr>
</table>
Range is a filter function:
angular.module('app').filter('range', function() {
return function(input, total) {
total = parseInt(total);
for (var i=0; i<total; i++)
input.push(i);
return input;
};
});
Note: This will only work when:
the rows,cols pair are sorted. If not you will have to sort them first and then bind it to the table
wont work for sparse arrays. In case of sparse arrays you will have to create dummy objects which should be ignored while creating the table
Also validate your JSON object in the question you posted before proceeding. It looks incorrect: http://jsonlint.com/
Upvotes: 2
Reputation: 3746
I have created a Plunkr for your solution - http://plnkr.co/edit/4vUm8yRiDKlTM8lnQH7E?p=preview.
To create the row/column for the table I have created 2 arrays - rows and columns.
$scope.rows = [];
for (var i=0;i<$scope.tableData.maxRows;i++) {
$scope.rows.push(i);
}
$scope.cols = [];
for (var i=0;i<$scope.tableData.maxCols;i++) {
$scope.cols.push(i);
}
The HTML has been kept as:
<table>
<tr ng-repeat="i in rows">
<td ng-repeat="j in cols">
<div table-pos object="tableData.questionsInTable" row="i" col="j"></div>
</td>
</tr>
</table>
table-pos is a directive that will accept the questions array, row and column index as scope attributes. I have used underscore.js for extracting the correct object from the collection of questions and display question for that position (based on rowPosition and colPosition). The code looks like below:
.directive("tablePos", function() {
return {
template: "<div>{{data}}</div>",
scope: {
object: "=",
row: "=",
col:"="
},
link: function(scope) {
var questions = scope.object;
var question= _.findWhere(questions, {colPosition:scope.col+1, rowPosition: scope.row+1});
scope.data = question.questionText;
}
}
})
The main advantage of using the directive is that there is no requirement for the questions in the list to be sorted in any order. So you can add questions in any order in your array. As long as the rowPosition and colPosition has been defined correctly the directive will pick it up.
Plus the directive also supports empty cells/sparse arrays, so if any question for a particular cell is not present, the directive will show empty data.
One drawback is that, if more than 1 question have the same rowPosition and colPosition then only the first question will be picked, and the remaining questions will be silently ignored.
Please note that in case you don't want to use underscope.js, you can still use plain JavaScript to detect the correct question from the list. However, usage of underscore.js makes it easier, as the underlying logic is abstracted.
Upvotes: 3