Reputation: 11376
I am trying to dynamically create a table in an angular directive. Following table creation i wish to populate the table with unknown data from my scope model. The tricky part of this is that i am not able to create my ng-repeat until after the linking function has built my table structure. I was hoping i could use the transclude function to accomplish this but it is not working and nothing is happening. all i see in my table is {{row.field0}} instead of the actual data value.
PS: the code sample below is in typescript.
Markup:
<table table-maker="" column-count="model.getColumnCount()" row-data="model.rowData">
</table>
Directive:
/// <reference path="../_references.ts" />
module Directives {
export interface ITableMakerScope extends ng.IScope {
columnCount: number;
rowData: any[];
}
export class TableMakerDirective {
public link: Function;
public transclude: boolean = true;
public scope: any = {
columnCount: '=',
rowData: '='
}
private _scope: ITableMakerScope;
private _element: JQuery;
constructor() {
this.link = this.internalLink.bind(this);
}
public internalLink(scope: ITableMakerScope, element: JQuery, attrs, ctrl): void {
this._scope = scope;
this._element = element;
var stopWatch = scope.$watch('columnCount', (newValue) => {
if (newValue) {
this.buildTable(newValue);
stopWatch();
}
});
}
private buildTable(columnCount: number): void {
var headerRow = $('<tr>');
var templateRow = $('<tr ng-repeat="row in rowData" ng-transclude="">'); // <-- angular
for (var i = 0; i < columnCount; i++) {
var th = $('<th>');
th.text('Column {0}'.format((i + 1).padLeft(1)));
headerRow.append(th);
var td = $('<td>');
td.text('{{row.field{0}}}'.format(i)); // <-- angular
templateRow.append(td);
}
var thead = $('<thead>');
thead.append(headerRow);
this._element.append(thead);
var tbody = $('<tbody>');
tbody.append(templateRow);
this._element.append(tbody);
}
}
}
Is this the right way to do this?
Thanks.
Upvotes: 0
Views: 1322
Reputation: 13043
Use the template
or templateUrl
property on the directive to hold your template information.
See the Angular documentation on directives
To pre-process the data I would do something like this (based on your example):
angular.module('moduleName').directive('tableMaker', function(){
return {
replace: true,
scope: {
columnCount: '=',
rowData: '='
},
link: function(scope, element, attr){
var columnCount = null;
var rowData = null;
// Set up watchers to detect changes to both properties.
scope.$watch('columnCount', function(value){
columnCount = value;
updateTable()
});
scope.$watchCollection('rowData', function(value){
rowData = value;
updateTable()
});
// This makes sure that we have both the columnCount and data before
// generating the table data.
function updateTable(){
var tableData = null;
if (columnCount && data){
tableData = buildTable(columnCount, data);
}
scope.tableData = tableData;
}
// Generate the data that will be used to create the table.
// Adjust as needed.
function buildTable(columnCount, rowData){
var tableData = {
headers: [],
rowData: rowData,
cellData: []
};
var headers = tableData.headers;
var cellData = tableData.cellData;
for (var i = 0; i < columnCount; i++){
headers.push('Column {0}'.format((i + 1).padLeft(1)));
cellData.push('field'+i);
}
return tableData;
}
},
template:
'<table>'+
'<thead>'+
'<tr>'+
'<th ng-repeat="header in tableData.headers">{{header}}</th>'+
'</tr>'+
'</thead>'+
'<tbody>'+
'<tr ng-repeat="row in tableData.rowData">'+
'<td ng-repeat="cell in tableData.cellData">{{row[cell]}}</td>'+
'</tr>'+
'</tbody>'+
'</table>'
};
});
Upvotes: 1